home *** CD-ROM | disk | FTP | other *** search
/ Varios Español / Varios Español.iso / CLIPP52 / TCBLLIB1.ZIP / LLIBGTOO.PRG < prev    next >
Text File  |  1993-11-23  |  196KB  |  5,374 lines

  1. #INCLUDE "llibg.ch"          // Include definitions file for Light Lib Graphics
  2. #INCLUDE "llibgtoo.ch"       // Include definitions file for Light Lib Graphics tools
  3.  
  4. #INCLUDE "Inkey.ch"
  5. #INCLUDE "Getexit.ch"
  6.  
  7.  
  8. STATIC aPrompt  := {}        // Static array to handle MENU TO replacement
  9.  
  10. STATIC aBmpBase := {}        // Static array to load majors .BMP in an INIT function
  11.  
  12. STATIC nPotRed    := 0       // Red   component of a color (Palette group)
  13. STATIC nPotGre    := 0       // Green component of a color (Palette group)
  14. STATIC nPotBlu    := 0       // Blue  component of a color (Palette group)
  15.  
  16. MEMVAR GetList               // Allow the use of public GetList variable
  17.                              // without warnings
  18.  
  19. *
  20.                              // Group Buttons
  21.                              // Note : Here are some CA-CLIPPER
  22.                              // functions to allow use of buttons
  23.                              // with mouse and BMP
  24. /***
  25. *
  26. *   LoadBmpBase()         Load the majors BMP when EXE start to avoid reloading
  27. *  aButtonAdd()           Add a button to a list
  28. *  lButtonKill()          Kill one or a list of buttons
  29. *   ButtonShowAll()       Show a list of buttonss
  30. *   ButtonDisplay()       Display one button
  31. *   XorButton()           XOR a button
  32. *
  33. *
  34. */
  35.  
  36. *
  37. #DEFINE ARROW_U_UP                       1    // Arrow Up       - Pos Up
  38. #DEFINE ARROW_U_DW                       2    // Arrow Up       - Pos Dw
  39. #DEFINE ARROW_D_UP                       3    // Arrow Dw       - Pos Up
  40. #DEFINE ARROW_D_DW                       4    // Arrow Dw       - Pos Dw
  41. #DEFINE ARROW_E_UP                       5    // Arrow Empty    - Pos Up
  42. #DEFINE ARROW_E_DW                       6    // Arrow Empty    - Pos Dw
  43. #DEFINE ARROW_L_UP                       7    // Arrow Left     - Pos Up
  44. #DEFINE ARROW_L_DW                       8    // Arrow Left     - Pos Dw
  45. #DEFINE ARROW_R_UP                       9    // Arrow Right    - Pos Up
  46. #DEFINE ARROW_R_DW                      10    // Arrow Right    - Pos Dw
  47. #DEFINE ARROW_G_UP                      11    // Arrow Get Up/Dw- Pos Up
  48. #DEFINE ARROW_G_DW                      12    // Arrow Get Up/DW- Pos Dw
  49. #DEFINE RADIO_E_UP                      13    // Radio Get Empty- Pos Up
  50. #DEFINE RADIO_E_DW                      14    // Radio Get Empty- Pos Dw
  51. #DEFINE RADIO_F_UP                      15    // Radio Get Full - Pos Up
  52. #DEFINE RADIO_F_DW                      16    // Radio Get Full - Pos Dw
  53. #DEFINE CHECK_E_UP                      17    // Check Get Empty- Pos Up
  54. #DEFINE CHECK_E_DW                      18    // Check Get Empty- Pos Dw
  55. #DEFINE CHECK_F_UP                      19    // Check Get Full - Pos Up
  56. #DEFINE CHECK_F_DW                      20    // Check Get Full - Pos Dw
  57. #DEFINE DROPBOX_UP                      21    // DropBox Get    - Pos Up
  58. #DEFINE DROPBOX_DW                      22    // DropBox Get    - Pos Dw
  59. #DEFINE CLOSWIN_UP                      23    // Close Window   - Pos Up
  60. #DEFINE CLOSWIN_DW                      24    // Close Window   - Pos Dw
  61.  
  62.  
  63. *
  64. INIT FUNCTION LoadBmpBase()
  65.                              // Load the majors BMP when EXE start to avoid reloading
  66.  
  67.    aBmpBase := {}
  68.  
  69.                              // Arrow Up
  70.    AADD(aBmpBase,gBmpLoad( "ARROW_U.BMU" ))
  71.    AADD(aBmpBase,gBmpLoad( "ARROW_U.BMD" ))
  72.  
  73.                              // Arrow Down
  74.    AADD(aBmpBase,gBmpLoad( "ARROW_D.BMU" ))
  75.    AADD(aBmpBase,gBmpLoad( "ARROW_D.BMD" ))
  76.  
  77.                              // Arrow Empty
  78.    AADD(aBmpBase,gBmpLoad( "ARROW_E.BMU" ))
  79.    AADD(aBmpBase,gBmpLoad( "ARROW_E.BMD" ))
  80.  
  81.                              // Arrow Left
  82.    AADD(aBmpBase,gBmpLoad( "ARROW_L.BMU" ))
  83.    AADD(aBmpBase,gBmpLoad( "ARROW_L.BMD" ))
  84.  
  85.                              // Arrow Right
  86.    AADD(aBmpBase,gBmpLoad( "ARROW_R.BMU" ))
  87.    AADD(aBmpBase,gBmpLoad( "ARROW_R.BMD" ))
  88.  
  89.                              // Arrow Get Up/Dw
  90.    AADD(aBmpBase,gBmpLoad( "ARROW_G.BMU" ))
  91.    AADD(aBmpBase,gBmpLoad( "ARROW_G.BMD" ))
  92.  
  93.                              // Radio Get Empty
  94.    AADD(aBmpBase,gBmpLoad( "RADIO_E.BMU" ))
  95.    AADD(aBmpBase,gBmpLoad( "RADIO_E.BMD" ))
  96.  
  97.                              // Radio Get Full
  98.    AADD(aBmpBase,gBmpLoad( "RADIO_F.BMU" ))
  99.    AADD(aBmpBase,gBmpLoad( "RADIO_F.BMD" ))
  100.  
  101.                              // Check Get Empty
  102.    AADD(aBmpBase,gBmpLoad( "CHECK_E.BMU" ))
  103.    AADD(aBmpBase,gBmpLoad( "CHECK_E.BMD" ))
  104.  
  105.                              // Check Get Full
  106.    AADD(aBmpBase,gBmpLoad( "CHECK_F.BMU" ))
  107.    AADD(aBmpBase,gBmpLoad( "CHECK_F.BMD" ))
  108.  
  109.                              // Drop box Get
  110.    AADD(aBmpBase,gBmpLoad( "DROPBOX.BMU" ))
  111.    AADD(aBmpBase,gBmpLoad( "DROPBOX.BMD" ))
  112.  
  113.                              // Close window
  114.    AADD(aBmpBase,gBmpLoad( "CLOSEWIN.BMU" ))
  115.    AADD(aBmpBase,gBmpLoad( "CLOSEWIN.BMD" ))
  116.  
  117.    RETURN (NIL)
  118.  
  119. *
  120. FUNCTION aButtonAdd(nButLeft     ,;    // Left coord in pixels
  121.                     nButTop      ,;    // Top coord in pixels
  122.                     nButRight    ,;    // Right coord in pixels
  123.                     nButBottom   ,;    // Bottom coord in pixels
  124.                     nButType     ,;    // Button Type (From LLibgToo.CH)
  125.                     xButAction   ,;    // Action (CodeBlock or Key value)
  126.                     xButAccel    ,;    // Accelerator Key (INKEY() value or string value)
  127.                     aButBmpUp    ,;    // Button representation in upper position (BMP,String,Block)
  128.                     aButBmpDown  ,;    // Button representation in down  position (BMP,String,Block)
  129.                     aButCtrls    ,;    // Array to attach the button
  130.                     xButCargo     ;    // Cargo value of the button
  131.                    )
  132.  
  133.                              // Add a button to a list
  134.  
  135.  
  136.    IF nButRight == NIL
  137.  
  138.       IF VALTYPE(aButBmpUp) == 'A'
  139.                              // The button size is deducted from the BMP size
  140.          nButRight := nButLeft + aButBmpUp[LLG_BMP_X] - 1
  141.  
  142.       ELSEIF VALTYPE(aButBmpUp) == 'C'
  143.                              // The button size is deducted from the length
  144.                              // of the string
  145.          nButRight := nButLeft + (LEN(aButBmpUp)+1)*FONT_SIZE_X - 1
  146.  
  147.       ELSEIF VALTYPE(aButBmpUp) == 'B'
  148.                              // The button size must be defined
  149.  
  150.       ENDIF
  151.  
  152.  
  153.    ENDIF
  154.  
  155.    IF nButBottom == NIL
  156.  
  157.       IF VALTYPE(aButBmpUp) == 'A'
  158.                              // The button size is deducted from the BMP size
  159.          nButBottom := nButTop + aButBmpUp[LLG_BMP_Y] - 1
  160.  
  161.       ELSEIF VALTYPE(aButBmpUp) == 'C'
  162.                              // The button size is deducted from font size
  163.          nButBottom := nButTop + FONT_SIZE_Y - 1
  164.  
  165.       ELSEIF VALTYPE(aButBmpUp) == 'B'
  166.                              // The button size must be defined
  167.  
  168.       ENDIF
  169.  
  170.    ENDIF
  171.  
  172.  
  173.    IF xButAccel==NIL         // If Accelerator key is undefined, default
  174.                              // to 0
  175.       xButAccel := 0
  176.  
  177.    ELSEIF VALTYPE(xButAccel)=='C'
  178.                              // If accelerator is defined as a string,
  179.                              // transform into ASCII value
  180.       xButAccel := ASC(xButAccel)
  181.  
  182.    ENDIF
  183.  
  184.    IF aButBmpUp == NIL       // If no button representation defined, default
  185.                              // to a empty block
  186.       aButBmpUp := { || NIL }
  187.    ENDIF
  188.  
  189.    IF aButBmpDown == NIL     // If no representation of Down button defined,
  190.                              // default to Up representation
  191.       aButBmpDown := aButBmpUp
  192.    ENDIF
  193.  
  194.                              // Add the button parameters to the handler
  195.    AADD(aButCtrls , { nButLeft             ,;
  196.                       nButTop              ,;
  197.                       nButRight            ,;
  198.                       nButBottom           ,;
  199.                       nButRight-nButLeft-1 ,;
  200.                       nButBottom-nButTop-1 ,;
  201.                       nButType             ,;
  202.                       xButAction           ,;
  203.                       aButBmpUp            ,;
  204.                       aButBmpDown          ,;
  205.                       xButAccel            ,;
  206.                       xButCargo             ;
  207.                     }                       ;
  208.        )
  209.  
  210.                              // Return the button parameters
  211.    RETURN (ATAIL(aButCtrls))
  212.  
  213.  
  214.  
  215.  
  216. *
  217. FUNCTION lButtonKill(aButCtrls   ,;    // List of related buttons
  218.                      nKillColor  ,;    // Color to be used to clear
  219.                      aButtonPtr   ;    // List of buttons to be cleared
  220.                     )
  221.                              // aButtonPtr == NIL --> Destroy all
  222.                              // aButtonPtr == Ptr --> Destroy one
  223.                              // aButtonPtr == Arr --> Destroy specified buttons
  224.  
  225.                              // Kill one or a list of buttons
  226.  
  227.    LOCAL nI      := 0
  228.    LOCAL nJ      := 0
  229.    LOCAL nLen    := LEN(aButCtrls)
  230.    LOCAL lKilled := .F.
  231.  
  232.  
  233.    IF aButtonPtr==NIL
  234.                              // Destroy all
  235.       IF nKillColor <> NIL
  236.  
  237.          FOR nI := 1 TO nLen
  238.  
  239.              gRect(aButCtrls[nJ,BUTTON_LEFT]   ,;
  240.                    aButCtrls[nJ,BUTTON_TOP ]   ,;
  241.                    aButCtrls[nJ,BUTTON_RIGHT]  ,;
  242.                    aButCtrls[nJ,BUTTON_BOTTOM] ,;
  243.                    LLG_FILL                    ,;
  244.                    nKillColor                  ,;
  245.                    LLG_MODE_SET                 ;
  246.                   )
  247.          NEXT nI
  248.  
  249.       ENDIF
  250.  
  251.       aButCtrls := {}
  252.  
  253.       RETURN( lKilled := .T. )
  254.  
  255.  
  256.    ELSEIF VALTYPE(aButtonPtr[1])<>'A'
  257.                              // Convert to the common case
  258.       aButtonPtr := { aButtonPtr }
  259.  
  260.    ENDIF
  261.  
  262.  
  263.    FOR nI := 1 TO LEN(aButtonPtr)
  264.                              // Find the ptr in the button list
  265.        IF (nJ := ASCAN(aButCtrls, { |aPtr| aPtr == aButtonPtr[nI] })) > 0 .AND. nJ <= nLen
  266.  
  267.           IF nKillColor <> NIL
  268.                              // If needed, clear area
  269.              gRect(aButCtrls[nJ,BUTTON_LEFT]    ,;
  270.                    aButCtrls[nJ,BUTTON_TOP ]    ,;
  271.                    aButCtrls[nJ,BUTTON_RIGHT]   ,;
  272.                    aButCtrls[nJ,BUTTON_BOTTOM]  ,;
  273.                    LLG_FILL                     ,;
  274.                    nKillColor                   ,;
  275.                    LLG_MODE_SET                  ;
  276.                   )
  277.           ENDIF
  278.                              // Resize ptr list
  279.           nLen--
  280.  
  281.           ASIZE(ADEL(aButCtrls,nJ),nLen)
  282.  
  283.           lKilled := .T.     // Button killed
  284.  
  285.        ENDIF
  286.  
  287.    NEXT nI
  288.  
  289.  
  290.    RETURN (lKilled)
  291.  
  292.  
  293. *
  294. FUNCTION ButtonShowAll(aButCtrls   ,;  // List of related buttons
  295.                        aButtonPtr   ;  // List of buttons to be displayed
  296.                       )
  297.                              // aButtonPtr == NIL --> Display all
  298.                              // aButtonPtr == Ptr --> Display one
  299.                              // aButtonPtr == Arr --> Display specified buttons
  300.  
  301.                              // Show a list of buttonss
  302.  
  303.    LOCAL nI   := 0
  304.    LOCAL nJ   := 0
  305.    LOCAL nLen := LEN(aButCtrls)
  306.  
  307.  
  308.    IF aButtonPtr==NIL
  309.                              // If list of ptr is empty, display all
  310.       FOR nJ := 1 TO nLen
  311.  
  312.           ButtonDisplay(aButCtrls[nJ],.T.)
  313.  
  314.       NEXT nI
  315.  
  316.       RETURN( NIL )
  317.  
  318.  
  319.    ELSEIF VALTYPE(aButtonPtr[1])<>'A'
  320.                              // Convert to the common case
  321.       aButtonPtr := { aButtonPtr }
  322.  
  323.    ENDIF
  324.  
  325.  
  326.    FOR nI := 1 TO LEN(aButtonPtr)
  327.                              // Find ptr in the button list
  328.        IF (nJ := ASCAN(aButCtrls, { |aPtr| aPtr == aButtonPtr[nI] })) > 0 .AND. nJ <= nLen
  329.                              // Display
  330.           ButtonDisplay(aButCtrls[nJ],.T.)
  331.  
  332.        ENDIF
  333.  
  334.    NEXT nI
  335.  
  336.  
  337.    RETURN (NIL)
  338.  
  339. *
  340. FUNCTION ButtonDisplay(aButton     ,;  // Button to be displayed
  341.                        lDisplayUp   ;  // Display on upper position
  342.                       )
  343.  
  344.                              // Display one button in up or down position
  345.  
  346.                              // Retrieve button style
  347.    LOCAL cButtonStyle := VALTYPE(IF(lDisplayUp,aButton[BUTTON_ICO_UP],aButton[BUTTON_ICO_DOWN]))
  348.  
  349.    IF cButtonStyle=='A'
  350.                              // Assume it is a .BMP array
  351.       gBmpDisp( IF( lDisplayUp                ,;
  352.                     aButton[BUTTON_ICO_UP]    ,;
  353.                     aButton[BUTTON_ICO_DOWN]   ;
  354.                   )                           ,;
  355.                aButton[BUTTON_LEFT]           ,;
  356.                aButton[BUTTON_TOP ]           ,;
  357.             )
  358.  
  359.    ELSEIF cButtonStyle=='C'
  360.                              // It's a text button, display on one line
  361.       gFrame(aButton[BUTTON_LEFT]          ,;
  362.              aButton[BUTTON_TOP ]          ,;
  363.              aButton[BUTTON_RIGHT]         ,;
  364.              aButton[BUTTON_BOTTOM]        ,;
  365.              07                            ,;
  366.              IF(lDisplayUp,00,15)          ,;
  367.              IF(lDisplayUp,15,00)          ,;
  368.              1, 1, 1, 1, LLG_MODE_SET       ;
  369.             )
  370.  
  371.       gWriteAt(aButton[BUTTON_LEFT]+(FONT_SIZE_X/2)+1  ,;
  372.                aButton[BUTTON_BOTTOM]-FONT_SIZE_Y+1    ,;
  373.                aButton[BUTTON_ICO_UP]                  ,;
  374.                0                                       ,;
  375.                LLG_MODE_SET                             ;
  376.               )
  377.  
  378.  
  379.    ELSEIF cButtonStyle=='B'
  380.                              // It's a use defined button, eval to display
  381.                              // pass button's coordinates to the code-block
  382.       EVAL(IF( lDisplayUp                ,;
  383.                aButton[BUTTON_ICO_UP]    ,;
  384.                aButton[BUTTON_ICO_DOWN]   ;
  385.              )                           ,;
  386.            aButton[BUTTON_LEFT]          ,;
  387.            aButton[BUTTON_TOP ]          ,;
  388.            aButton[BUTTON_RIGHT]         ,;
  389.            aButton[BUTTON_BOTTOM]        ,;
  390.            aButton[BUTTON_CARGO]          ;
  391.           )
  392.  
  393.    ENDIF
  394.  
  395.  
  396.  
  397.    RETURN (NIL)
  398.  
  399.  
  400. *
  401. FUNCTION XorButton(nLeft   ,;          // Left coord in pixels
  402.                    nTop    ,;          // Top coord in pixels
  403.                    nRight  ,;          // Right coord in pixels
  404.                    nBottom  ;          // Bottom coord in pixels
  405.                   )
  406.  
  407.                              // XOR a button
  408.                              // Note : when your XOR and reXOR a button, you
  409.                              // get the original display back
  410.     gRect(nLeft        ,;
  411.           nTop         ,;
  412.           nRight       ,;
  413.           nBottom      ,;
  414.           LLG_FILL     ,;
  415.           15           ,;
  416.           LLG_MODE_XOR  ;
  417.          )
  418.  
  419.    RETURN (NIL)
  420.  
  421. *
  422.                              // Group mInkey() / Buttons
  423.                              // Note : Here are some CA-CLIPPER
  424.                              // functions to allow use of buttons, mouse and
  425.                              // Keyboard with mInkey()
  426. /***
  427. *
  428. *   mInkey()              Replaceable INKEY() function
  429. *   nApplyMouse()         Apply a mouse action to buttons lists
  430. *   nApplyKey()           Apply a accelerator key to buttons lists
  431. *   nHitGet()             Set/Get function to allow mousable gets
  432. *   lMouseInButton()      Is the mouse inside a button
  433. *   aWhichButton()        Find the button corresponding to mouse location
  434. *
  435. */
  436.  
  437.  
  438. *
  439. FUNCTION mInkey(nSeconds  ,;   // Classical INKEY() parameter
  440.                 aButCtrls ,;   // Array of buttons defined with aButtonAdd()
  441.                 aGetList   ;   // For use in GetSys.prg, to be able to track buttons OR Gets
  442.                )
  443.  
  444.                                // mInkey() function is a replacement function for
  445.                                // INKEY() function. Passing aButCtrls parameter
  446.                                // allow you to defined and manage buttons in a couple
  447.                                // of seconds. When the user hit a button with the
  448.                                // mouse, mInkey() manage all events associated.
  449.                                // If the button's action is a code-block, mInkey()
  450.                                // EVAL this code-block with 3 parameters, mouse X
  451.                                // coordinate, mouse Y coordinate and button Ptr.
  452.                                // nReturn take the K_BUTTON value and the function
  453.                                // returns, which allows you to process button and
  454.                                // keys in the same way. (see tbdemo.prg)
  455.                                // If the user clic out of all the buttons from the
  456.                                // list, mInkey() return K_CLIC_OUT
  457.                                // If the user strike an accelerator key, the action
  458.                                // is executed and the K_ACCELERATOR value is returned.
  459.                                // When a get is hitted, the K_GET value is returned
  460.  
  461.  
  462.    LOCAL nReturn     :=  0         // Return value of mInkey() function
  463.    LOCAL lLeft       := .F.        // Left mouse button hitted
  464.    LOCAL lRight      := .F.        // Right mouse button hitted
  465.    LOCAL nTime       :=  0         // Time controler
  466.    LOCAL aMouseState := mState()   // Mouse state array
  467.  
  468.  
  469.  
  470.    IF aButCtrls==NIL         // Default aButCtrls to an array
  471.       aButCtrls:={}
  472.    ENDIF
  473.  
  474.    IF aGetList==NIL          // Default aGetList to an array
  475.       aGetList:={}
  476.    ENDIF
  477.  
  478.                              // turn on the mouse cursor
  479.    mShow()
  480.  
  481.    IF nSeconds == NIL        // Wait for a key or a mouse action
  482.  
  483.       IF aMouseState[LLM_STATE_LEFT] == LLM_BUTTON_DOWN
  484.                              // Left button is down
  485.                              // Apply mouse action to buttons and gets lists
  486.          nReturn := nApplyMouse(aMouseState, aButCtrls, aGetList)
  487.  
  488.       ELSE
  489.                              // Get key (if any) and apply key
  490.                              // to buttons and gets lists
  491.          nReturn := nApplyKey(INKEY(), aButCtrls, aGetList)
  492.  
  493.       ENDIF
  494.  
  495.    ELSE                      // wait for either a keystroke, a left
  496.                              // button click, or until nSeconds have elapsed
  497.  
  498.       nTime := SECONDS()     // Initialize timer controler
  499.  
  500.       WHILE ( nReturn := INKEY()) == 0                                     .AND. ;
  501.             !(lLeft  := (aMouseState[LLM_STATE_LEFT]  == LLM_BUTTON_DOWN)) .AND. ;
  502.             !(lRight := (aMouseState[LLM_STATE_RIGHT] == LLM_BUTTON_DOWN)) .AND. ;
  503.             IIF (nSeconds > 0,  (SECONDS() - nTime) < nSeconds, .T.)
  504.  
  505.            aMouseState := mState()
  506.  
  507.       ENDDO
  508.  
  509.       IF lLeft               // Left button is down
  510.                              // Apply mouse action to buttons and gets lists
  511.          nReturn := nApplyMouse(aMouseState, aButCtrls, aGetList)
  512.  
  513.       ELSEIF lRight          // Right button is down
  514.  
  515.          nReturn := K_CLIC_OUT
  516.  
  517.       ELSEIF nReturn <> 0    // a key have been striked, apply
  518.  
  519.          nReturn := nApplyKey(nReturn, aButCtrls, aGetList)
  520.  
  521.       ENDIF
  522.  
  523.    ENDIF
  524.                              // hide the mouse cursor
  525.    mHide()
  526.  
  527. RETURN( nReturn )
  528.  
  529.  
  530. *
  531. STATIC FUNCTION nApplyKey(nKey     ,; // Key value
  532.                          aButCtrls ,; // Array of buttons defined with aButtonAdd()
  533.                          aGetList   ; // For use in GetSys.prg, to be able to track buttons OR Gets
  534.                         )
  535.  
  536.                              // Apply a keystroke to the button list
  537.    LOCAL nReturn := nKey
  538.    LOCAL nI      := 0
  539.  
  540.    IF aButCtrls<>NIL         // If buttons are defined, try to find if
  541.                              // the key is an accelerator key
  542.  
  543.       IF (nKey >= 65 .AND. nKey <=  90) .OR. ;
  544.          (nKey >= 97 .AND. nKey <= 122)
  545.                        // If the key is in A-Z or a-z range, take uppercase value
  546.  
  547.          nI := ASC(UPPER(CHR(nKey)))
  548.  
  549.       ELSE             // Else take the value
  550.  
  551.          nI := nKey
  552.  
  553.       ENDIF
  554.  
  555.       IF (nI := ASCAN( aButCtrls , { |el| el[BUTTON_ACCELERATOR]==nI } ))<>0
  556.                              // If the key matches an accelerator key
  557.          mHide()
  558.  
  559.                              // Display the button in down position
  560.          ButtonDisplay(aButCtrls[nI],.F.)
  561.  
  562.  
  563.          IF aButCtrls[nI,BUTTON_TYPE]==BUTTON_TYPE_KEY
  564.                              // If the button emulate a key stroke,
  565.                              // just transalte the value
  566.             nReturn := aButCtrls[nI,BUTTON_ACTION]
  567.  
  568.             TONE(0,4)        // Wait 4/18 of seconds before to release the button
  569.  
  570.                              // Display in up position
  571.             ButtonDisplay(aButCtrls[nI],.T.)
  572.  
  573.  
  574.          ELSE                // A code-block must be executed
  575.                              // As the mouse is not involved, use 0,0 parameters
  576.             EVAL(aButCtrls[nI,BUTTON_ACTION],0,0,aButCtrls[nI])
  577.  
  578.                              // Display in up position
  579.             ButtonDisplay(aButCtrls[nI],.T.)
  580.  
  581.             mShow()
  582.                              // Return K_ACCELERATOR value as the action
  583.                              // have already be executed
  584.             nReturn := K_ACCELERATOR
  585.  
  586.          ENDIF
  587.  
  588.       ENDIF
  589.  
  590.    ENDIF
  591.  
  592.    RETURN( nReturn )
  593.  
  594.  
  595.  
  596. *
  597. STATIC FUNCTION nApplyMouse(aMouseState ,; // Mouses values
  598.                             aButCtrls   ,; // Array of buttons defined with aButtonAdd()
  599.                             aGetList     ; // For use in GetSys.prg, to be able to track buttons OR Gets
  600.                            )
  601.  
  602.                              // Apply a mouse action to the button list
  603.  
  604.    LOCAL nReturn     :=  0   // Value to returned by mInkey()
  605.    LOCAL aHitButton  := {}   // Hitted button ptr, if any
  606.    LOCAL nTimeStart  := 0    // Timer to delay mouse tracking
  607.  
  608.    LOCAL nRow        :=  0   // Mouse row
  609.    LOCAL nCol        :=  0   // Mouse col
  610.    LOCAL nGet        :=  0   // Position in GetList
  611.    LOCAL aMouseClip  := {}   // Mouse clipping area
  612.  
  613.    mHide()
  614.  
  615.                              // Look in the buttons table
  616.    IF (aHitButton := aWhichButton(aButCtrls              ,;
  617.                                   aMouseState[LLM_STATE_X]  ,;
  618.                                   aMouseState[LLM_STATE_Y]   ;
  619.                                  )                           ;
  620.       ) == NIL
  621.  
  622.       nReturn := 0           // No button find
  623.  
  624.    ELSE
  625.                              // Clic on aHitButton
  626.  
  627.       mHide()
  628.  
  629.                              // Display in down position
  630.       ButtonDisplay(aHitButton,.F.)
  631.  
  632.  
  633.       IF aHitButton[BUTTON_TYPE]==BUTTON_TYPE_KEY
  634.                              // The button emulates a key stroke
  635.  
  636.          mShow()
  637.                              // Wait for the mouse to be released inside the button
  638.          DO WHILE ( aMouseState := mState() )[LLM_STATE_LEFT] == LLM_BUTTON_DOWN .AND. ;
  639.                   lMouseInButton(aHitButton,aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y])
  640.          ENDDO
  641.  
  642.          mHide()
  643.  
  644.                              // If the mouse have been released inside the button
  645.          IF lMouseInButton(aHitButton,aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y])
  646.                              // Return the emulated value
  647.             nReturn := aHitButton[BUTTON_ACTION]
  648.  
  649.          ENDIF
  650.  
  651.       ELSE
  652.  
  653.          IF aHitButton[BUTTON_TYPE]==BUTTON_TYPE_RELEASE
  654.                              // The button must be released before
  655.                              // action to executed
  656.             mShow()
  657.                              // Wait for the mouse to be released inside the button
  658.             DO WHILE ( aMouseState := mState() )[LLM_STATE_LEFT] == LLM_BUTTON_DOWN .AND. ;
  659.                      lMouseInButton(aHitButton,aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y])
  660.             ENDDO
  661.  
  662.             mHide()
  663.  
  664.                              // If the mouse have been released inside the button
  665.             IF lMouseInButton(aHitButton,aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y])
  666.  
  667.                              // EVAL action code block with mouse X-Y and button ptr
  668.                EVAL(aHitButton[BUTTON_ACTION],aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y],aHitButton)
  669.  
  670.             ENDIF
  671.  
  672.  
  673.          ELSEIF aHitButton[BUTTON_TYPE]==BUTTON_TYPE_REPEAT
  674.                              // The action must be repeated as long as the
  675.                              // mouse is down
  676.  
  677.                              // Initialise a timer
  678.             nTimeStart := SECONDS()
  679.  
  680.                              // Save previous mouse clipping
  681.             aMouseClip := mSetClip()
  682.  
  683.                              // EVAL action code block a first time
  684.                              // with mouse X-Y and button ptr
  685.             EVAL(aHitButton[BUTTON_ACTION],aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y],aHitButton)
  686.  
  687.             mShow()
  688.  
  689.                              // Wait a little bit before to repeat action
  690.             DO WHILE (SECONDS() < nTimeStart + 0.5) .AND. ( aMouseState := mState() )[LLM_STATE_LEFT] == LLM_BUTTON_DOWN .AND. lMouseInButton(aHitButton,aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y])
  691.             ENDDO
  692.  
  693.                              // Force the mouse to stay inside the button
  694.             mSetClip(aHitButton[BUTTON_LEFT]    ,;
  695.                      aHitButton[BUTTON_TOP]     ,;
  696.                      aHitButton[BUTTON_RIGHT]   ,;
  697.                      aHitButton[BUTTON_BOTTOM]  ,;
  698.                      LLM_COOR_GRAPH              ;
  699.                     )
  700.  
  701.             DO WHILE ( aMouseState := mState() )[LLM_STATE_LEFT] == LLM_BUTTON_DOWN .AND. lMouseInButton(aHitButton,aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y])
  702.                              // While the mouse is down
  703.                mHide()
  704.  
  705.                              // EVAL action code block with mouse X-Y and button ptr
  706.                EVAL(aHitButton[BUTTON_ACTION],aMouseState[LLM_STATE_X],aMouseState[LLM_STATE_Y],aHitButton)
  707.  
  708.                mShow()
  709.  
  710.             ENDDO
  711.  
  712.  
  713.                              // Restore previous mouse clipping area
  714.             mSetClip(aMouseClip[1]   ,;
  715.                      aMouseClip[2]   ,;
  716.                      aMouseClip[3]   ,;
  717.                      aMouseClip[4]   ,;
  718.                      LLM_COOR_GRAPH   ;
  719.                     )
  720.  
  721.          ENDIF
  722.  
  723.  
  724.          nReturn := K_BUTTON  // A code-block button have been hitted
  725.  
  726.       ENDIF
  727.  
  728.       mHide()
  729.                        // Display in up position
  730.       ButtonDisplay(aHitButton,.T.)
  731.  
  732.       mShow()
  733.  
  734.    ENDIF
  735.                              // The clic is not inside controls buttons, try
  736.                              //  Gets if any
  737.    IF nReturn == 0  .AND. LEN(aGetList)>0
  738.  
  739.                              // Make it faster
  740.       nRow := aMouseState[LLM_STATE_ROW]
  741.       nCol := aMouseState[LLM_STATE_COL]
  742.  
  743.                              // Find the clic inside the gets list
  744.       nGet := Ascan(aGetList                                                ,;
  745.                     { |o| nRow==o:row .AND.                                  ;
  746.                           nCol>=o:Col .AND.                                  ;
  747.                           nCol<=o:Col+Len(Transform(o:Varget(),o:picture))-1 ;
  748.                      }                                                       ;
  749.                     )
  750.                              // If a get have been hitted
  751.       IF nGet<>0
  752.          nHitGet(nGet)       // Set the value to allow it to be retrieve in GetSys
  753.          nReturn := K_GET    // Set the return value to K_GET
  754.       ENDIF
  755.  
  756.    ENDIF
  757.  
  758.                              // If 0, convert to K_CLIC_OUT
  759.    RETURN( IF(nReturn==0,K_CLIC_OUT,nReturn) )
  760.  
  761. *
  762. FUNCTION nHitGet(nGet)       // SetGet function used to manage mouse in gets
  763.  
  764.    STATIC nHitGet
  765.    LOCAL  nOldHitGet := nHitGet
  766.  
  767.    IF ( PCOUNT() > 0 )
  768.       nHitGet := nGet
  769.    ENDIF
  770.  
  771.    RETURN nOldHitGet
  772.  
  773.  
  774. *
  775. FUNCTION lMouseInButton(aButton ,; // Button ptr
  776.                         nMouseX ,; // Mouse X position
  777.                         nMouseY  ; // Mouse Y position
  778.                        )
  779.  
  780.                              // Return .T. if mouse is insode button
  781.  
  782.    RETURN( nMouseX >= aButton[BUTTON_LEFT  ] .AND. ;
  783.            nMouseY >= aButton[BUTTON_TOP   ] .AND. ;
  784.            nMouseX <= aButton[BUTTON_RIGHT ] .AND. ;
  785.            nMouseY <= aButton[BUTTON_BOTTOM]       ;
  786.          )
  787.  
  788.  
  789. *
  790. FUNCTION aWhichButton(aButCtrls ,; // Buttons list
  791.                       nMouseX   ,; // Mouse X position
  792.                       nMouseY    ; // Mouse Y position
  793.                      )
  794.  
  795.                              // Find the button clicked, if any
  796.  
  797.    LOCAL nI         := 0               // Loop indice
  798.    LOCAL nMaxButton := LEN(aButCtrls)  // Len of buttons list
  799.    LOCAL nHitButton := 0               // Hitted button position
  800.  
  801.                              // Look in the list in reverse order
  802.                              // this allow to partially cover a large button
  803.                              // with a smaller one (ie scrollbar)
  804.  
  805.    FOR nI := nMaxButton TO 1 STEP -1
  806.  
  807.        IF lMouseInButton(aButCtrls[nI],nMouseX,nMouseY)
  808.                              // If the mouse is inside the button
  809.           nHitButton := nI
  810.  
  811.           EXIT
  812.  
  813.        ENDIF
  814.  
  815.    NEXT nI
  816.                              // Return NIL or the button's ptr
  817.    RETURN (IF(nHitButton==0,NIL,aButCtrls[nHitButton]))
  818.  
  819.  
  820. *
  821.                              // Group ScrollBar
  822.                              // Note : Here are some CA-CLIPPER
  823.                              // functions to allow use of scrollbrs in TBROWSE
  824.                              // and others situations
  825. /***
  826. *
  827. *   aScrollAdd()          Add a ScrollBar to a list of buttons
  828. *    ScrArrowAction()     Execute action mapped to arrows buttons
  829. *    ScrCursorAction()    Execute action mapped to cursor button
  830. *    ScrBarAction()       Execute action mapped to bar button
  831. *    ScrBarDisplay()      Update scrollbar display
  832. *    ScrBarUpDate()       Update scrollbar internals
  833. *
  834. */
  835.  
  836. *
  837. FUNCTION aScrollAdd(nScrollLeft     ,;  // Scrollbar coordinates
  838.                     nScrollTop      ,;  // in graphics mode
  839.                     nScrollRight    ,;  // If vertical, must be 16 pixels width
  840.                     nScrollBottom   ,;  // If Horizontal, must be 16 pixels height
  841.                     nScrollType     ,;  // BUTTON_TYPE_SCROLL_VERT or BUTTON_TYPE_SCROLL_HORI
  842.                     bArrow1Action   ,;  // Code-block for left or top button
  843.                     bArrow2Action   ,;  // Code-block for Right or bottom button
  844.                     bScrollCompute  ,;  // Compute code block
  845.                     aButCtrls       ,;  // Button list master handler
  846.                     aScrollPtr       ;  // Ptr on this scrollbar
  847.                    )
  848.  
  849.                              // Add a scrollbar to a list of buttons
  850.                              // a scrollbar is a combination of 4 buttons
  851.                              // Left/right/bar/cursor. We also need to be
  852.                              // able to refresh the scrollbar if the related
  853.                              // object (ie tbrowse ...) is moved, that is the
  854.                              // reason why we need a ptr on each scrollbar.
  855.                              // Top/Left and Bottom/Right code-block are obvious
  856.                              // bScrollCompute is a little be more tricky.
  857.                              // You should study BrowseHori() in this source
  858.                              // file to understand the way it runs.
  859.  
  860.  
  861.    LOCAL nButInCtrls := 0    // Number of buttons in the controls list, before
  862.                              // we add the scrollbar buttons
  863.  
  864.  
  865.    IF nScrollType == BUTTON_TYPE_SCROLL_VERT
  866.                              // Vertical scroll bar
  867.  
  868.                              // Add the arrow up button
  869.                              // It's a repeat button
  870.       aButtonAdd(nScrollLeft                             ,;
  871.                  nScrollTop                              ,;
  872.                  NIL                                     ,;
  873.                  NIL                                     ,;
  874.                  BUTTON_TYPE_REPEAT                      ,;
  875.                  { |nMouseX,nMouseY| ScrArrowAction(nMouseX, nMouseY, -1, bArrow1Action, bScrollCompute, aScrollPtr) } ,;
  876.                  NIL                                     ,;
  877.                  aBmpBase[ARROW_U_UP]                    ,;
  878.                  aBmpBase[ARROW_U_DW]                    ,;
  879.                  aButCtrls                                ;
  880.                 )                                         ;
  881.  
  882.  
  883.  
  884.                              // Add the arrow down button
  885.                              // It's a repeat button
  886.       aButtonAdd(nScrollLeft                             ,;
  887.                  nScrollBottom-FONT_SIZE_Y               ,;
  888.                  NIL                                     ,;
  889.                  NIL                                     ,;
  890.                  BUTTON_TYPE_REPEAT                  ,;
  891.                  { |nMouseX,nMouseY| ScrArrowAction(nMouseX, nMouseY,  1, bArrow2Action, bScrollCompute, aScrollPtr) } ,;
  892.                  NIL                                     ,;
  893.                  aBmpBase[ARROW_D_UP]                    ,;
  894.                  aBmpBase[ARROW_D_DW]                    ,;
  895.                  aButCtrls                                ;
  896.                 )                                         ;
  897.  
  898.  
  899.                              // Draw the bar itself
  900.       gRect( nScrollLeft                  ,;
  901.              nScrollTop+FONT_SIZE_Y       ,;
  902.              nScrollRight-1               ,;
  903.              nScrollBottom-FONT_SIZE_Y    ,;
  904.              LLG_FILL                     ,;
  905.              8                            ,;
  906.              LLG_MODE_SET                  ;
  907.            )
  908.  
  909.                              // Add the large bar button
  910.                              // It's a release button
  911.       aButtonAdd(nScrollLeft                                                       ,;
  912.                  nScrollTop+FONT_SIZE_Y                                            ,;
  913.                  nScrollRight-1                                                    ,;
  914.                  nScrollBottom-FONT_SIZE_Y                                         ,;
  915.                  BUTTON_TYPE_RELEASE                                           ,;
  916.                  { |nMouseX,nMouseY,aButton| ScrBarAction(nMouseX                  ,;
  917.                                                           nMouseY                  ,;
  918.                                                           aButton                  ,;
  919.                                                           bScrollCompute           ,;
  920.                                                           nScrollLeft              ,;
  921.                                                           nScrollTop+FONT_SIZE_Y   ,;
  922.                                                           nScrollRight-1           ,;
  923.                                                           nScrollBottom-FONT_SIZE_Y,;
  924.                                                           nScrollType              ,;
  925.                                                           aButCtrls                ,;
  926.                                                           aScrollPtr                ;
  927.                                                          )                          ;
  928.                  }                                                                 ,;
  929.                  NIL                                                               ,;
  930.                  NIL                                                               ,;
  931.                  NIL                                                               ,;
  932.                  aButCtrls                                                          ;
  933.                 )                                                                   ;
  934.  
  935.                              // Add the cursor button
  936.                              // It's a repeat button
  937.       aButtonAdd(nScrollLeft                                                                                 ,;
  938.                  (nScrollTop+FONT_SIZE_Y)+(nScrollBottom-nScrollTop-3*FONT_SIZE_Y)*EVAL(bScrollCompute,NIL,NIL)+1          ,;
  939.                  NIL                                                                                         ,;
  940.                  NIL                                                                                         ,;
  941.                  BUTTON_TYPE_REPEAT                                                                          ,;
  942.                  { |nMouseX,nMouseY,aButton| ScrCursorAction(nMouseX                                         ,;
  943.                                                              nMouseY                                         ,;
  944.                                                              aButton                                         ,;
  945.                                                              bScrollCompute                                  ,;
  946.                                                              nScrollLeft                                     ,;
  947.                                                              nScrollTop+FONT_SIZE_Y+1                        ,;
  948.                                                              nScrollRight-1                                  ,;
  949.                                                              nScrollBottom-FONT_SIZE_Y-1                     ,;
  950.                                                              nScrollType                                     ,;
  951.                                                              aButCtrls                                       ,;
  952.                                                              aScrollPtr                                       ;
  953.                                                             )                                                 ;
  954.                  }                                                                                           ,;
  955.                  NIL                                                                                         ,;
  956.                  aBmpBase[ARROW_E_UP]                                                                        ,;
  957.                  aBmpBase[ARROW_E_DW]                                                                        ,;
  958.                  aButCtrls                                                                                    ;
  959.                 )                                                                                             ;
  960.  
  961.  
  962.    ELSEIF nScrollType == BUTTON_TYPE_SCROLL_HORI
  963.                              // Horizontal scroll bar
  964.  
  965.                              // Add the arrow left button
  966.                              // It's a repeat button
  967.       aButtonAdd(nScrollLeft                             ,;
  968.                  nScrollBottom-FONT_SIZE_Y               ,;
  969.                  NIL                                     ,;
  970.                  NIL                                     ,;
  971.                  BUTTON_TYPE_REPEAT                  ,;
  972.                  { |nMouseX,nMouseY| ScrArrowAction(nMouseX, nMouseY, -1, bArrow1Action, bScrollCompute,aScrollPtr) } ,;
  973.                  NIL                                     ,;
  974.                  aBmpBase[ARROW_L_UP]                    ,;
  975.                  aBmpBase[ARROW_L_DW]                    ,;
  976.                  aButCtrls                                ;
  977.                 )                                         ;
  978.  
  979.  
  980.  
  981.                              // Add the arrow right button
  982.                              // It's a repeat button
  983.       aButtonAdd(nScrollRight-2*FONT_SIZE_X              ,;
  984.                  nScrollBottom-FONT_SIZE_Y               ,;
  985.                  NIL                                     ,;
  986.                  NIL                                     ,;
  987.                  BUTTON_TYPE_REPEAT                  ,;
  988.                  { |nMouseX,nMouseY| ScrArrowAction(nMouseX, nMouseY,  1, bArrow2Action, bScrollCompute, aScrollPtr) } ,;
  989.                  NIL                                     ,;
  990.                  aBmpBase[ARROW_R_UP]                    ,;
  991.                  aBmpBase[ARROW_R_DW]                    ,;
  992.                  aButCtrls                                ;
  993.                 )                                         ;
  994.  
  995.  
  996.                              // Draw the bar itself
  997.       gRect( nScrollLeft+2*FONT_SIZE_X  ,;
  998.              nScrollTop                 ,;
  999.              nScrollRight-2*FONT_SIZE_X ,;
  1000.              nScrollBottom-1            ,;
  1001.              LLG_FILL                   ,;
  1002.              8                          ,;
  1003.              LLG_MODE_SET                ;
  1004.            )
  1005.  
  1006.                              // Add the large bar button
  1007.                              // It's a release button
  1008.       aButtonAdd(nScrollLeft+2*FONT_SIZE_X                                          ,;
  1009.                  nScrollTop                                                         ,;
  1010.                  nScrollRight-2*FONT_SIZE_X                                         ,;
  1011.                  nScrollBottom-1                                                    ,;
  1012.                  BUTTON_TYPE_RELEASE                                            ,;
  1013.                  { |nMouseX,nMouseY,aButton| ScrBarAction(nMouseX                   ,;
  1014.                                                           nMouseY                   ,;
  1015.                                                           aButton                   ,;
  1016.                                                           bScrollCompute            ,;
  1017.                                                           nScrollLeft+2*FONT_SIZE_X ,;
  1018.                                                           nScrollTop                ,;
  1019.                                                           nScrollRight-2*FONT_SIZE_X,;
  1020.                                                           nScrollBottom-1           ,;
  1021.                                                           nScrollType               ,;
  1022.                                                           aButCtrls                 ,;
  1023.                                                           aScrollPtr                 ;
  1024.                                                          )                           ;
  1025.                  }                                                                  ,;
  1026.                  NIL                                                                ,;
  1027.                  NIL                                                                ,;
  1028.                  NIL                                                                ,;
  1029.                  aButCtrls                                                           ;
  1030.                 )                                                                    ;
  1031.  
  1032.                              // Add the cursor button
  1033.                              // It's a repeat button
  1034.       aButtonAdd((nScrollLeft+2*FONT_SIZE_X)+(nScrollRight-nScrollLeft-6*FONT_SIZE_X)*EVAL(bScrollCompute,NIL,NIL) ,;
  1035.                  nScrollTop                                                                                   ,;
  1036.                  NIL                                                                                          ,;
  1037.                  NIL                                                                                          ,;
  1038.                  BUTTON_TYPE_REPEAT                                                                           ,;
  1039.                  { |nMouseX,nMouseY,aButton| ScrCursorAction(nMouseX                                          ,;
  1040.                                                              nMouseY                                          ,;
  1041.                                                              aButton                                          ,;
  1042.                                                              bScrollCompute                                   ,;
  1043.                                                              nScrollLeft+2*FONT_SIZE_X                        ,;
  1044.                                                              nScrollTop                                       ,;
  1045.                                                              nScrollRight-2*FONT_SIZE_X                       ,;
  1046.                                                              nScrollBottom-1                                  ,;
  1047.                                                              nScrollType                                      ,;
  1048.                                                              aButCtrls                                        ,;
  1049.                                                              aScrollPtr                                        ;
  1050.                                                             )                                                  ;
  1051.                  }                                                                                            ,;
  1052.                  NIL                                                                                          ,;
  1053.                  aBmpBase[ARROW_E_UP]                                                                         ,;
  1054.                  aBmpBase[ARROW_E_DW]                                                                         ,;
  1055.                  aButCtrls                                                                                     ;
  1056.                 )                                                                                              ;
  1057.  
  1058.    ENDIF
  1059.  
  1060.    nButInCtrl := LEN(aButCtrls)
  1061.  
  1062.    AADD(aScrollPtr, aButCtrls[nButInCtrl-3] )   // Left or top button
  1063.    AADD(aScrollPtr, aButCtrls[nButInCtrl-2] )   // Right or bottom button
  1064.    AADD(aScrollPtr, aButCtrls[nButInCtrl-1] )   // bar button
  1065.    AADD(aScrollPtr, aButCtrls[nButInCtrl]   )   // cursor button
  1066.    AADD(aScrollPtr, nScrollType             )   // Scrollbar type
  1067.  
  1068.    RETURN ( aScrollPtr )
  1069.  
  1070.  
  1071. *
  1072. FUNCTION ScrArrowAction(nMouseX        ,; // Mouse X location
  1073.                         nMouseY        ,; // Mouse Y location
  1074.                         nSens          ,; // Move direction (-1=>left/up 1=>Right/down)
  1075.                         bArrow1Action  ,; // Action linked to the button
  1076.                         bScrollCompute ,; // Percentage code-block
  1077.                         aScrollPtr      ; // Ptr on Scroll
  1078.                        )
  1079.                              // Eval action
  1080.    EVAL(bArrow1Action,nMouseX,nMouseY)
  1081.  
  1082.                             // Update scrollbar location
  1083.    ScrBarUpDate(aScrollPtr,EVAL(bScrollCompute,nSens,0))
  1084.  
  1085.    RETURN (NIL)
  1086.  
  1087.  
  1088.  
  1089. *
  1090. FUNCTION ScrCursorAction(nMouseX         ,; // Mouse X location
  1091.                          nMouseY         ,; // Mouse Y location
  1092.                          aButCur         ,; // Ptr on cursor button
  1093.                          bScrollCompute  ,; // Percentage code-block
  1094.                          nScrollLeft     ,; // Scroll pixels coordinates
  1095.                          nScrollTop      ,; //
  1096.                          nScrollRight    ,; //
  1097.                          nScrollBottom   ,; //
  1098.                          nScrollType     ,; // Scrolltype (Hori|vert)
  1099.                          aButCtrls       ,; // List of all buttons
  1100.                          aScrollPtr       ; // Ptr on scroll
  1101.                         )
  1102.  
  1103.    LOCAL nPercent  := 0      // Cursor position (in %) in the scrollbar
  1104.  
  1105.                              // Ptr on the cursor button
  1106.    LOCAL aButBar := aScrollPtr[3]
  1107.  
  1108.  
  1109.                              // While the mouse is inside the button
  1110.    IF ( nMouseX >= nScrollLeft   .AND. ;
  1111.         nMouseY >= nScrollTop    .AND. ;
  1112.         nMouseX <= nScrollRight  .AND. ;
  1113.         nMouseY <= nScrollBottom       ;
  1114.       )
  1115.  
  1116.  
  1117.       IF nScrollType == BUTTON_TYPE_SCROLL_VERT
  1118.                              // Vertical scroll
  1119.  
  1120.                              // Force mouse to stay inside the bar
  1121.          IF nMouseY <= nScrollTop+(FONT_SIZE_Y/2)
  1122.             nMouseY := nScrollTop+(FONT_SIZE_Y/2)
  1123.          ENDIF
  1124.          IF nMouseY >= nScrollBottom-(FONT_SIZE_Y/2)
  1125.             nMouseY := nScrollBottom-(FONT_SIZE_Y/2)
  1126.          ENDIF
  1127.                              // Compute a % value
  1128.          nPercent := (nMouseY-nScrollTop-(FONT_SIZE_Y/2))/(nScrollBottom-nScrollTop-FONT_SIZE_Y)
  1129.  
  1130.                              // Move the button coodinate
  1131.          aButCur[BUTTON_TOP]    := nMouseY-(FONT_SIZE_Y/2)
  1132.          aButCur[BUTTON_BOTTOM] := aButCur[BUTTON_TOP] + aButCur[BUTTON_HEIGHT]
  1133.  
  1134.  
  1135.       ELSEIF nScrollType == BUTTON_TYPE_SCROLL_HORI
  1136.                              // Horizontal scroll
  1137.  
  1138.                              // Force mouse to stay inside the bar
  1139.          IF nMouseX <= nScrollLeft+FONT_SIZE_X
  1140.             nMouseX := nScrollLeft+FONT_SIZE_X
  1141.          ENDIF
  1142.          IF nMouseX >= nScrollRight-FONT_SIZE_X
  1143.             nMouseX := nScrollRight-FONT_SIZE_X
  1144.          ENDIF
  1145.  
  1146.  
  1147.                              // Compute a % value
  1148.          nPercent := (nMouseX-nScrollLeft-FONT_SIZE_X)/(nScrollRight-nScrollLeft-2*FONT_SIZE_X)
  1149.  
  1150.                              // Move the button coodinate
  1151.          aButCur[BUTTON_LEFT]  := nMouseX-FONT_SIZE_X
  1152.          aButCur[BUTTON_RIGHT] := aButCur[BUTTON_LEFT] + aButCur[BUTTON_WIDTH]
  1153.  
  1154.       ENDIF
  1155.  
  1156.  
  1157.                              // Reset clipping area (the cursor button is
  1158.                              // a repeat button, so a clipping area have been
  1159.                              // defined and need to be moved as the button is moved
  1160.       mSetClip( aButCur[BUTTON_LEFT]    ,;
  1161.                 aButCur[BUTTON_TOP]     ,;
  1162.                 aButCur[BUTTON_RIGHT]   ,;
  1163.                 aButCur[BUTTON_BOTTOM]  ,;
  1164.                 LLM_COOR_GRAPH           ;
  1165.              )
  1166.  
  1167.                              // Redisplay all the bar with cursor button in
  1168.                              // down position
  1169.       ScrBarDisplay(aButBar      ,;
  1170.                     aButCur      ,;
  1171.                     nScrollType  ,;
  1172.                     .F.           ;
  1173.                    )
  1174.  
  1175.  
  1176.                              // EVAL the compute block with the new value
  1177.       EVAL(bScrollCompute,0,nPercent)
  1178.  
  1179.    ENDIF
  1180.  
  1181.  
  1182.  
  1183. RETURN (NIL)
  1184.  
  1185.  
  1186. *
  1187. FUNCTION ScrBarAction(nMouseX         ,; // Mouse X location
  1188.                       nMouseY         ,; // Mouse Y location
  1189.                       aButBar         ,; // Ptr on bar button
  1190.                       bScrollCompute  ,; // Percentage code-block
  1191.                       nScrollLeft     ,; // Scroll pixels coordinates
  1192.                       nScrollTop      ,; //
  1193.                       nScrollRight    ,; //
  1194.                       nScrollBottom   ,; //
  1195.                       nScrollType     ,; // Scrolltype (Hori|vert)
  1196.                       aButCtrls       ,; // List of all buttons
  1197.                       aScrollPtr       ; // Ptr on scroll
  1198.                      )
  1199.  
  1200.    LOCAL nPercent  := 0      // Cursor position (in %) in the scrollbar
  1201.  
  1202.                              // Ptr on the bar button
  1203.    LOCAL aButCur := aScrollPtr[4]
  1204.  
  1205.  
  1206.    IF nScrollType == BUTTON_TYPE_SCROLL_VERT
  1207.                              // Vertical scroll
  1208.  
  1209.                              // Force mouse to stay inside the bar
  1210.       IF nMouseY <= nScrollTop+(FONT_SIZE_Y/2)
  1211.          nMouseY := nScrollTop+(FONT_SIZE_Y/2)
  1212.       ENDIF
  1213.       IF nMouseY >= nScrollBottom-(FONT_SIZE_Y/2)
  1214.          nMouseY := nScrollBottom-(FONT_SIZE_Y/2)
  1215.       ENDIF
  1216.  
  1217.                              // Compute a % value
  1218.       nPercent := (nMouseY-nScrollTop-(FONT_SIZE_Y/2))/(nScrollBottom-nScrollTop-FONT_SIZE_Y)
  1219.  
  1220.                              // Move the button coordinates
  1221.       aButCur[BUTTON_TOP]    := nMouseY-(FONT_SIZE_Y/2)
  1222.       aButCur[BUTTON_BOTTOM] := aButCur[BUTTON_TOP] + aButCur[BUTTON_HEIGHT]
  1223.  
  1224.  
  1225.    ELSEIF nScrollType == BUTTON_TYPE_SCROLL_HORI
  1226.                              // Horizontal scroll
  1227.  
  1228.                              // Force mouse to stay inside the bar
  1229.       IF nMouseX <= nScrollLeft+FONT_SIZE_X
  1230.          nMouseX := nScrollLeft+FONT_SIZE_X
  1231.       ENDIF
  1232.       IF nMouseX >= nScrollRight-FONT_SIZE_X
  1233.          nMouseX := nScrollRight-FONT_SIZE_X
  1234.       ENDIF
  1235.  
  1236.                              // Compute a % value
  1237.       nPercent := (nMouseX-nScrollLeft-FONT_SIZE_X)/(nScrollRight-nScrollLeft-2*FONT_SIZE_X)
  1238.  
  1239.                              // Move the button coordinates
  1240.       aButCur[BUTTON_LEFT]   := nMouseX-FONT_SIZE_X
  1241.       aButCur[BUTTON_RIGHT]  := aButCur[BUTTON_LEFT] + aButCur[BUTTON_WIDTH]
  1242.  
  1243.    ENDIF
  1244.  
  1245.                              // EVAL the compute block with the new value
  1246.    EVAL(bScrollCompute,0,nPercent)
  1247.  
  1248.                              // Redisplay all the bar with cursor button in
  1249.                              // up position
  1250.    ScrBarDisplay(aButBar      ,;
  1251.                  aButCur      ,;
  1252.                  nScrollType  ,;
  1253.                  .T.           ;
  1254.                 )
  1255.  
  1256.  
  1257.    RETURN (NIL)
  1258.  
  1259.  
  1260.  
  1261.  
  1262. *
  1263. FUNCTION ScrBarDisplay(aButBar      ,; // Bar button ptr
  1264.                        aButCur      ,; // Cursor button ptr
  1265.                        nScrollType  ,; // Scrollbar type
  1266.                        lDisplayUp    ; // Display mode
  1267.                       )
  1268.  
  1269.    mHide()
  1270.  
  1271.    IF nScrollType == BUTTON_TYPE_SCROLL_VERT
  1272.                              // Vertical scroll
  1273.  
  1274.                              // Clear the upperside of the stripe
  1275.       gRect( aButBar[BUTTON_LEFT]  ,;
  1276.              aButBar[BUTTON_TOP]+1 ,;
  1277.              aButBar[BUTTON_RIGHT] ,;
  1278.              aButCur[BUTTON_TOP]-1 ,;
  1279.              LLG_FILL              ,;
  1280.              8                     ,;
  1281.              LLG_MODE_SET           ;
  1282.            )
  1283.  
  1284.                              // Display the cursor
  1285.       gBmpDisp( IF( lDisplayUp                ,;
  1286.                     aButCur[BUTTON_ICO_UP]    ,;
  1287.                     aButCur[BUTTON_ICO_DOWN]   ;
  1288.                   )                           ,;
  1289.                aButCur[BUTTON_LEFT]           ,;
  1290.                aButCur[BUTTON_TOP ]           ,;
  1291.             )
  1292.  
  1293.                              // Clear the down side of the stripe
  1294.       gRect( aButBar[BUTTON_LEFT]     ,;
  1295.              aButCur[BUTTON_BOTTOM]+2 ,;
  1296.              aButBar[BUTTON_RIGHT]    ,;
  1297.              aButBar[BUTTON_BOTTOM]-1 ,;
  1298.              LLG_FILL                 ,;
  1299.              8                        ,;
  1300.              LLG_MODE_SET              ;
  1301.            )
  1302.  
  1303.    ELSEIF nScrollType == BUTTON_TYPE_SCROLL_HORI
  1304.                              // Horizontal scroll
  1305.  
  1306.                              // Clear the left of the stripe
  1307.       gRect( aButBar[BUTTON_LEFT]+1 ,;
  1308.              aButBar[BUTTON_TOP]    ,;
  1309.              aButCur[BUTTON_LEFT]-1 ,;
  1310.              aButBar[BUTTON_BOTTOM] ,;
  1311.              LLG_FILL               ,;
  1312.              8                      ,;
  1313.              LLG_MODE_SET            ;
  1314.            )
  1315.  
  1316.                              // Display the cursor
  1317.       gBmpDisp( IF( lDisplayUp                ,;
  1318.                     aButCur[BUTTON_ICO_UP]    ,;
  1319.                     aButCur[BUTTON_ICO_DOWN]   ;
  1320.                   )                           ,;
  1321.                aButCur[BUTTON_LEFT]           ,;
  1322.                aButCur[BUTTON_TOP ]           ,;
  1323.             )
  1324.  
  1325.                              // Clear the right of the stripe
  1326.       gRect( aButCur[BUTTON_RIGHT]+2 ,;
  1327.              aButBar[BUTTON_TOP]     ,;
  1328.              aButBar[BUTTON_RIGHT]-1 ,;
  1329.              aButBar[BUTTON_BOTTOM]  ,;
  1330.              LLG_FILL                ,;
  1331.              8                       ,;
  1332.              LLG_MODE_SET             ;
  1333.            )
  1334.  
  1335.    ENDIF
  1336.  
  1337.    mShow()
  1338.  
  1339.    RETURN (NIL)
  1340.  
  1341. *
  1342. FUNCTION ScrBarUpDate(aScroll    ,; // Ptr on scrollbar
  1343.                       nPercent    ; // Percentage
  1344.                       )
  1345.  
  1346.    LOCAL nPos        := 0           // Position in pixels
  1347.    LOCAL aButBar     := aScroll[3]  // Bar button
  1348.    LOCAL aButCur     := aScroll[4]  // Cursor button
  1349.    LOCAL nScrollType := aScroll[5]  // Scroll type
  1350.  
  1351.  
  1352.    IF nScrollType == BUTTON_TYPE_SCROLL_VERT
  1353.                              // Vertical scroll
  1354.  
  1355.                              // Compute the cursor position
  1356.       nPos := nPercent*(aButBar[BUTTON_BOTTOM]-aButBar[BUTTON_TOP]-FONT_SIZE_Y)+aButBar[BUTTON_TOP]+(FONT_SIZE_Y/2)
  1357.  
  1358.                              // Move the button coordinates
  1359.       aButCur[BUTTON_TOP]    := nPos-(FONT_SIZE_Y/2)
  1360.       aButCur[BUTTON_BOTTOM] := aButCur[BUTTON_TOP] + aButCur[BUTTON_HEIGHT]
  1361.  
  1362.  
  1363.    ELSEIF nScrollType == BUTTON_TYPE_SCROLL_HORI
  1364.                              // Horizontal scroll
  1365.  
  1366.                              // Compute the cursor position
  1367.       nPos := nPercent*(aButBar[BUTTON_RIGHT]-aButBar[BUTTON_LEFT]-2*FONT_SIZE_X)+aButBar[BUTTON_LEFT]+FONT_SIZE_X
  1368.  
  1369.                              // Move the button coordinates
  1370.       aButCur[BUTTON_LEFT]   := nPos-FONT_SIZE_X
  1371.       aButCur[BUTTON_RIGHT]  := aButCur[BUTTON_LEFT] + aButCur[BUTTON_WIDTH]
  1372.  
  1373.  
  1374.    ENDIF
  1375.                              // Display scrollbar with cursor in up position
  1376.    ScrBarDisplay(aButBar      ,;
  1377.                  aButCur      ,;
  1378.                  nScrollType  ,;
  1379.                  .T.           ;
  1380.                 )
  1381.  
  1382.  
  1383.    RETURN (NIL)
  1384.  
  1385.  
  1386. *
  1387.                              // Group Potentiometers
  1388.                              // Note : Here are some CA-CLIPPER
  1389.                              // functions to allow use of potentiometers
  1390. /***
  1391. *
  1392. *   aPotAdd()             Create a new potentiometers
  1393. *   nPotSetGet()          Manage changes in potentiometer value
  1394. *   nPotDisplay()         Display pictured value left to potentiometer
  1395. *
  1396. */
  1397.  
  1398.  
  1399. *
  1400. FUNCTION aPotAdd(nPotLeft        ,;  // Left in columns
  1401.                  nPotTop         ,;  // Top in rows
  1402.                  nPotWidth       ,;  // Width in columns
  1403.                  bValSetGet      ,;  // Set/Get block
  1404.                  bExeChange      ,;  // Block to execute when value change
  1405.                  nValMin         ,;  // Minimum value
  1406.                  nValMax         ,;  // Maximum value
  1407.                  cValPic         ,;  // Picture value
  1408.                  aButCtrls       ,;  // General button handler
  1409.                  aPotent          ;  // This object handler
  1410.                 )
  1411.  
  1412.                              // Create a new potentiometer
  1413.  
  1414.                              // Translate values to pixels
  1415.    LOCAL nLeft     := nPotLeft * FONT_SIZE_X
  1416.    LOCAL nTop      := nPotTop * FONT_SIZE_Y
  1417.    LOCAL nBottom   := (nPotTop+1) * FONT_SIZE_Y
  1418.    LOCAL nRightMid := 0
  1419.    LOCAL nRightEnd := 0
  1420.  
  1421.                              // Default to NIL code-block
  1422.    IF bExeChange == NIL
  1423.       bExeChange := { || NIL }
  1424.    ENDIF
  1425.                              // Default minimum value to 0
  1426.    IF nValMin == NIL
  1427.       nValMin := 0
  1428.    ENDIF
  1429.                              // Default maximum value to 100
  1430.    IF nValMax == NIL
  1431.       nValMax := 100
  1432.    ENDIF
  1433.                              // Default picture value to '999%'
  1434.    IF cValPic == NIL
  1435.       cValPic := "999%"
  1436.    ENDIF
  1437.                              // Compute end of scrollbar and begining of
  1438.                              // pictured display
  1439.    nRightMid := (nPotLeft+nPotWidth-LEN(cValPic))*FONT_SIZE_X
  1440.    nRightEnd := (nPotLeft+nPotWidth)*FONT_SIZE_X
  1441.  
  1442.                              // Create a scroll
  1443.    aScrollAdd(nLeft                                        ,;
  1444.               nTop                                         ,;
  1445.               nRightMid                                    ,;
  1446.               nBottom                                      ,;
  1447.               BUTTON_TYPE_SCROLL_HORI                      ,;
  1448.               { |nMouseX,nMouseY| nPotSetGet(bValSetGet,nValMin,nValMax,cValPic,   -1,     NIL,nRightMid,nTop,nRightEnd,nBottom,bExeChange)  }    ,;
  1449.               { |nMouseX,nMouseY| nPotSetGet(bValSetGet,nValMin,nValMax,cValPic,    1,     NIL,nRightMid,nTop,nRightEnd,nBottom,bExeChange)  }    ,;
  1450.               { |nSens,nPercent|  nPotSetGet(bValSetGet,nValMin,nValMax,cValPic,nSens,nPercent,nRightMid,nTop,nRightEnd,nBottom,bExeChange)  }    ,;
  1451.               aButCtrls                                    ,;
  1452.               aPotent                                       ;
  1453.              )
  1454.  
  1455.    AADD(aPotent, { |nValue| nPotDisplay(nValue, cValPic, nRightMid,nTop,nRightEnd,nBottom ) } )
  1456.  
  1457.                              // Initialize values
  1458.    nPotSetGet(bValSetGet,nValMin,nValMax,cValPic,  NIL,     NIL,nRightMid,nTop,nRightEnd,nBottom,bExeChange)
  1459.  
  1460.    RETURN (aPotent)
  1461.  
  1462. *
  1463. FUNCTION nPotSetGet(bValSetGet ,; // Get/Set block
  1464.                     nValMin    ,; // Minimum value
  1465.                     nValMax    ,; // Maximum value
  1466.                     cValPic    ,; // Picture
  1467.                     nSens      ,; // NIL, -1 , 1
  1468.                     nPercent   ,; // NIL, 0 , -1 , 1
  1469.                     nLeft      ,; // pictured value frame location in pixels
  1470.                     nTop       ,; //
  1471.                     nRight     ,; //
  1472.                     nBottom    ,; //
  1473.                     bExeChange  ; // Block to be executed when the value change
  1474.                    )
  1475.  
  1476.                              // Manage changes in potentiometer value
  1477.  
  1478.                              // Retrieve value from Get/Set block
  1479.    LOCAL nValue    := EVAL(bValSetGet)
  1480.  
  1481.    IF nSens <> NIL           // If nSens is not NIL, value must be SET
  1482.  
  1483.  
  1484.       IF nSens == 0          // If nSens==0, value is deducted from nPercent
  1485.  
  1486.          nValue := EVAL( bValSetGet , nValMin+INT((nValMax-nValMin)*nPercent) )
  1487.  
  1488.       ELSE                   // Increment or decrement value
  1489.  
  1490.                              // Use Get/Set block to set new value
  1491.          nValue := EVAL( bValSetGet , nValue+nSens )
  1492.  
  1493.                              // Minimize - Maximize value
  1494.          IF nValue < nValMin
  1495.             nValue := EVAL( bValSetGet , nValMin )
  1496.          ELSEIF nValue>nValMax
  1497.             nValue := EVAL( bValSetGet , nValMax )
  1498.          ENDIF
  1499.  
  1500.       ENDIF
  1501.  
  1502.    ENDIF
  1503.                              // Display pictured value
  1504.    nPotDisplay(nValue, cValPic, nLeft, nTop, nRight, nBottom )
  1505.  
  1506.                              // Eval something when value changes
  1507.    EVAL(bExeChange)
  1508.  
  1509.    RETURN ((nValue-nValMin)/(nValMax-nValMin))
  1510.  
  1511. *
  1512. FUNCTION nPotDisplay(nValue     ,; // Value to be displayed
  1513.                      cValPic    ,; // Picture
  1514.                      nLeft      ,; // pictured value frame location in pixels
  1515.                      nTop       ,; //
  1516.                      nRight     ,; //
  1517.                      nBottom     ; //
  1518.                     )
  1519.  
  1520.                              // Display pictured value left to potentiometer
  1521.  
  1522.                              // Display a frame
  1523.    gFrame( nLeft     ,;
  1524.            nTop      ,;
  1525.            nRight    ,;
  1526.            nBottom-1 ,;
  1527.             7, 15, 8, 1, 1, 1, 1, LLG_MODE_SET )
  1528.  
  1529.                              // Write value inside
  1530.    gWriteAt( nLeft+1                   ,;
  1531.              nTop+1                    ,;
  1532.              TRANSFORM(nValue,cValPic) ,;
  1533.              0                         ,;
  1534.              LLG_MODE_SET               ;
  1535.           )
  1536.  
  1537.    RETURN (NIL)
  1538.  
  1539. *
  1540.                              // Group Odometer/Gauge
  1541.                              // Note : Here are some CA-CLIPPER
  1542.                              // functions to allow use of odometers and gauges
  1543. /***
  1544. *
  1545. *   lOdometer()           Create/Use/Delete an odometer
  1546. *   lGauge()              Create/Use/Delete a gauge
  1547. *
  1548. */
  1549.  
  1550. *
  1551. FUNCTION lOdometer(xMode   ,; // ODOME_INIT | ODOME_IDLE==(NIL) | ODOME_EXIT
  1552.                    aHandle ,; // NIL if only one object at a time, a {} ptr in the other cases
  1553.                    nTop    ,; // Location in column
  1554.                    nLeft    ; // Location in row
  1555.                   )
  1556.  
  1557.                              // Create/Use/Delete an odometer
  1558.  
  1559.    LOCAL  lContinue  := .T.  // Default return value
  1560.                              // Couples of coordinates
  1561.    STATIC aPoints    := {                                         { 8, 3} , { 9, 3} , {10, 3} , {11, 3} , {12, 3} ,;
  1562.                           {12, 4} , {12, 5} , {12, 6} , {12, 7} , {12, 8} , {12, 9} , {12,10} , {12,11} , {12,12} ,;
  1563.                           {11,12} , {10,12} , { 9,12} , { 8,12} , { 7,12} , { 6,12} , { 5,12} , { 4,12} , { 3,12} ,;
  1564.                           { 3,11} , { 3,10} , { 3, 9} , { 3, 8} , { 3, 7} , { 3, 6} , { 3, 5} , { 3, 4} , { 3, 3} ,;
  1565.                           { 4, 3} , { 5, 3} , { 6, 3} , { 7, 3}                                                    ;
  1566.                         }
  1567.  
  1568.    STATIC aDefHandle := {}   // Default handle if not defined
  1569.  
  1570.    IF aHandle<>NIL           // If an handle is define, use the defined one
  1571.       aDefHandle := aHandle
  1572.    ENDIF
  1573.  
  1574.    IF xMode == ODOME_IDLE    // idle case
  1575.  
  1576.  
  1577.       aDefHandle[8]++        // increase the value
  1578.                              // each turn, change color by switching .T./.F.
  1579.       IF aDefHandle[8] > 36
  1580.          aDefHandle[8] := 1
  1581.          aDefHandle[9] := !aDefHandle[9]
  1582.       ENDIF
  1583.                              // gLine from the center to one of the point
  1584.       gLine(aDefHandle[4]                           ,;
  1585.             aDefHandle[5]                           ,;
  1586.             aDefHandle[6]+aPoints[aDefHandle[8],1]  ,;
  1587.             aDefHandle[7]+aPoints[aDefHandle[8],2]  ,;
  1588.             IF(aDefHandle[9],2,4)                   ,;
  1589.             LLG_MODE_SET                             ;
  1590.           )
  1591.  
  1592.  
  1593.       IF INKEY()==K_ESC      // If ESC, return a .F. value
  1594.          lContinue := .F.
  1595.       ENDIF
  1596.  
  1597.    ELSEIF xMode == ODOME_INIT
  1598.                              // Init case
  1599.  
  1600.       ASIZE(aDefHandle,0)    // Resize aDefHandle if needed
  1601.  
  1602.                                                    //  1 - Save back
  1603.       AADD(aDefHandle,SAVESCREEN(nTop,nLeft,nTop,nLeft+1))
  1604.       AADD(aDefHandle,nTop)                        //  2 - Top in row
  1605.       AADD(aDefHandle,nLeft)                       //  3 - Left in row
  1606.       AADD(aDefHandle,(nLeft+1)*FONT_SIZE_X)       //  4 - X center in pixels
  1607.       AADD(aDefHandle,(nTop+.5)*FONT_SIZE_Y)       //  5 - Y center in pixels
  1608.       AADD(aDefHandle,nLeft*FONT_SIZE_X)           //  6 - Left in pixels
  1609.       AADD(aDefHandle,nTop*FONT_SIZE_Y)            //  7 - Top in pixels
  1610.       AADD(aDefHandle,1)                           //  8 - Last position
  1611.       AADD(aDefHandle,.T.)                         //  9 - Color switch
  1612.  
  1613.                              // Display a frame
  1614.       gFrame(nLeft*FONT_SIZE_X              ,;
  1615.              nTop*FONT_SIZE_Y               ,;
  1616.              (nLeft+2)*FONT_SIZE_X-1        ,;
  1617.              (nTop+1)*FONT_SIZE_Y-1         ,;
  1618.              07                             ,;
  1619.              15                             ,;
  1620.              00                             ,;
  1621.              3, 3, 3, 3, LLG_MODE_SET        ;
  1622.              )
  1623.  
  1624.  
  1625.    ELSEIF xMode == ODOME_EXIT
  1626.                              // Exit case
  1627.  
  1628.                              // Restore the screen
  1629.       RESTSCREEN(aDefHandle[2],aDefHandle[3],aDefHandle[2],aDefHandle[3]+1,aDefHandle[1])
  1630.                              // Resize the handle
  1631.                              // (do not replace by aDefHandle:={} to allow caller
  1632.                              // function to point on the same value)
  1633.       ASIZE(aDefHandle,0)
  1634.  
  1635.    ENDIF
  1636.  
  1637.  
  1638.    RETURN (lContinue)
  1639.  
  1640. *
  1641. FUNCTION lGauge(xMode   ,; // GAUGE_INIT | GAUGE_IDLE==(NIL) | GAUGE_EXIT
  1642.                 aHandle ,; // NIL if only one object at a time, a {} ptr in the other cases
  1643.                 nType   ,; // Gauge type GAUGE_HORI | GAUGE_VERT
  1644.                 nTop    ,; // Location in column
  1645.                 nLeft   ,; // Location in row
  1646.                 nExtend ,; // Lenght or width in column or row
  1647.                 bMaxVal ,; // Maximum value to be reached
  1648.                 bCurVal  ; // Curent value, should be in 0-Max value range
  1649.                )
  1650.  
  1651.    LOCAL lContinue := .T.    // Default return value
  1652.    LOCAL nI        := 0      // For/next loop indice
  1653.  
  1654.    STATIC aDefHandle := {}   // Default handle if not defined
  1655.  
  1656.    IF aHandle<>NIL           // If an handle is define, use the defined one
  1657.       aDefHandle := aHandle
  1658.    ENDIF
  1659.  
  1660.    IF xMode == GAUGE_IDLE    // Idle case
  1661.  
  1662.  
  1663.       IF aDefHandle[12]==GAUGE_HORI
  1664.                              // Horizontal gauge
  1665.  
  1666.                              // Display a rectangle from left to the value
  1667.          gRect(aDefHandle[4]                                                   ,;
  1668.                aDefHandle[5]                                                   ,;
  1669.                aDefHandle[4]+(aDefHandle[3]*EVAL(aDefHandle[7])/aDefHandle[2]) ,;
  1670.                aDefHandle[6]                                                   ,;
  1671.                LLG_FILL                                                        ,;
  1672.                2                                                               ,;
  1673.                LLG_MODE_SET                                                     ;
  1674.             )
  1675.  
  1676.       ELSEIF aDefHandle[12]==GAUGE_VERT
  1677.                              // Vertical gauge
  1678.  
  1679.                              // Display a rectangle from bottom to the value
  1680.          gRect(aDefHandle[4]                                                   ,;
  1681.                aDefHandle[6]                                                   ,;
  1682.                aDefHandle[5]                                                   ,;
  1683.                aDefHandle[6]-(aDefHandle[3]*EVAL(aDefHandle[7])/aDefHandle[2]) ,;
  1684.                LLG_FILL                                                        ,;
  1685.                2                                                               ,;
  1686.                LLG_MODE_SET                                                     ;
  1687.             )
  1688.  
  1689.       ENDIF
  1690.  
  1691.       IF INKEY()==K_ESC      // If ESC, return a .F. value
  1692.          lContinue := .F.
  1693.       ENDIF
  1694.  
  1695.    ELSEIF xMode == GAUGE_INIT
  1696.                              // Init case
  1697.  
  1698.       ASIZE(aDefHandle,0)    // Resize aDefHandle if needed
  1699.  
  1700.       IF nType==GAUGE_HORI
  1701.                              // Horizontal gauge
  1702.  
  1703.                                                       //  1 - Save gauge back
  1704.          AADD(aDefHandle,SAVESCREEN(nTop,nLeft,nTop+1,nLeft+nExtend))
  1705.          AADD(aDefHandle,EVAL(bMaxVal))               //  2 - Max value
  1706.          AADD(aDefHandle,nExtend*FONT_SIZE_X-6)       //  3 - Width available in pixels
  1707.          AADD(aDefHandle,nLeft*FONT_SIZE_X+3)         //  4 - Left available
  1708.          AADD(aDefHandle,nTop*FONT_SIZE_Y+3)          //  5 - Top available
  1709.          AADD(aDefHandle,(nTop+1)*FONT_SIZE_Y-4)      //  6 - Bottom available
  1710.          AADD(aDefHandle,bCurVal)                     //  7 - Block to retrieve current value
  1711.          AADD(aDefHandle,nTop)                        //  8 - Top of save screen
  1712.          AADD(aDefHandle,nLeft)                       //  9 - Left ...
  1713.          AADD(aDefHandle,nTop+1)                      // 10 - Bottom ...
  1714.          AADD(aDefHandle,nLeft+nExtend)               // 11 - Right ...
  1715.          AADD(aDefHandle,nType)                       // 12 - Type Hori/Vert
  1716.  
  1717.                              // Display gauge frame
  1718.          gFrame(nLeft*FONT_SIZE_X              ,;
  1719.                nTop*FONT_SIZE_Y                ,;
  1720.                (nLeft+nExtend)*FONT_SIZE_X     ,;
  1721.                (nTop+1)*FONT_SIZE_Y-1          ,;
  1722.                07                              ,;
  1723.                15                              ,;
  1724.                00                              ,;
  1725.                3, 3, 3, 3, LLG_MODE_SET         ;
  1726.                )
  1727.                              // Display 9 separators
  1728.          FOR nI := 1 TO 9
  1729.             gLine(aDefHandle[4]+aDefHandle[3]*nI/10   ,;
  1730.                   aDefHandle[6]                       ,;
  1731.                   aDefHandle[4]+aDefHandle[3]*nI/10   ,;
  1732.                   aDefHandle[6]-IF(nI==5,5,2)         ,;
  1733.                   00                                  ,;
  1734.                   LLG_MODE_SET                         ;
  1735.                   )
  1736.          NEXT nI
  1737.  
  1738.       ELSEIF nType==GAUGE_VERT
  1739.                              // Vertical gauge
  1740.  
  1741.                                                       //  1 - Save gauge back
  1742.          AADD(aDefHandle,SAVESCREEN(nTop,nLeft,nTop+nExtend,nLeft+2))
  1743.          AADD(aDefHandle,EVAL(bMaxVal))               //  2 - Max value
  1744.          AADD(aDefHandle,nExtend*FONT_SIZE_Y-6)       //  3 - Height available in pixels
  1745.          AADD(aDefHandle,nLeft*FONT_SIZE_X+3)         //  4 - Left available
  1746.          AADD(aDefHandle,(nLeft+2)*FONT_SIZE_X-4)     //  5 - Right available
  1747.          AADD(aDefHandle,(nTop+nExtend)*FONT_SIZE_Y-4)//  6 - Bottom available
  1748.          AADD(aDefHandle,bCurVal)                     //  7 - Block to retrieve current value
  1749.          AADD(aDefHandle,nTop)                        //  8 - Top of save screen
  1750.          AADD(aDefHandle,nLeft)                       //  9 - Left ...
  1751.          AADD(aDefHandle,nTop+nExtend)                // 10 - Bottom ...
  1752.          AADD(aDefHandle,nLeft+2)                     // 11 - Right ...
  1753.          AADD(aDefHandle,nType)                       // 12 - Type Hori/Vert
  1754.  
  1755.  
  1756.                              // Display gauge frame
  1757.          gFrame(nLeft*FONT_SIZE_X              ,;
  1758.                nTop*FONT_SIZE_Y                ,;
  1759.                (nLeft+2)*FONT_SIZE_X-1         ,;
  1760.                (nTop+nExtend)*FONT_SIZE_Y-1    ,;
  1761.                07                              ,;
  1762.                15                              ,;
  1763.                00                              ,;
  1764.                3, 3, 3, 3, LLG_MODE_SET         ;
  1765.                )
  1766.  
  1767.                              // Display 9 separators
  1768.          FOR nI := 1 TO 9
  1769.             gLine(aDefHandle[4]                     ,;
  1770.                   aDefHandle[6]-aDefHandle[3]*nI/10 ,;
  1771.                   aDefHandle[4]+IF(nI==5,5,2)       ,;
  1772.                   aDefHandle[6]-aDefHandle[3]*nI/10 ,;
  1773.                   00                                ,;
  1774.                   LLG_MODE_SET                       ;
  1775.                   )
  1776.          NEXT nI
  1777.  
  1778.       ENDIF
  1779.  
  1780.  
  1781.    ELSEIF xMode == GAUGE_EXIT
  1782.                              // Exit case
  1783.  
  1784.                              // Restore the screen
  1785.       RESTSCREEN(aDefHandle[8],aDefHandle[9],aDefHandle[10],aDefHandle[11],aDefHandle[1])
  1786.                              // Resize the handle
  1787.                              // (do not replace by aDefHandle:={} to allow caller
  1788.                              // function to point on the same value)
  1789.       ASIZE(aDefHandle,0)
  1790.  
  1791.    ENDIF
  1792.  
  1793.  
  1794.    RETURN (lContinue)
  1795.  
  1796.  
  1797. *
  1798.                              // Group TBDEMO
  1799.                              // Note : Here are some CA-CLIPPER
  1800.                              // functions to allow use of scrollbar in TBDEMO
  1801. /***
  1802. *
  1803. *   BrowseVert()          Link database and screen pointer
  1804. *   BrowseHori()          Link database and screen pointer
  1805. *   BrowseClic()          Manage clic inside browse cells
  1806. *
  1807. */
  1808.  
  1809. *
  1810. FUNCTION BrowseVert(nSens     ,;  // NIL, -1, 0, 1
  1811.                     nPercent  ,;  // NIL or 0 to 1
  1812.                     oBrowse    ;  // Browse pointer
  1813.                    )
  1814.  
  1815.  
  1816.    IF nSens <> NIL           // Move the pointer
  1817.  
  1818.       IF nSens == 0          // Set the position depending on %
  1819.                              // MAX Prevent from DBGOTO(0) when % is small
  1820.          DBGOTO(INT(MAX(1,nPercent*LASTREC())))
  1821.          oBrowse:refreshAll()
  1822.  
  1823.       ELSEIF nSens == -1     // Move up
  1824.  
  1825.          oBrowse:up()
  1826.  
  1827.       ELSEIF nSens == 1      // Move down
  1828.  
  1829.          oBrowse:down()
  1830.  
  1831.       ENDIF
  1832.  
  1833.    ELSE                      // nSens==NIL just mean : what is location in %
  1834.  
  1835.    ENDIF
  1836.  
  1837.                              // Return location in %
  1838.    RETURN (RECNO()/LASTREC())
  1839.  
  1840.  
  1841.  
  1842. *
  1843. FUNCTION BrowseHori(nSens     ,;  // NIL, -1, 0, 1
  1844.                     nPercent  ,;  // NIL or 0 to 1
  1845.                     oBrowse    ;  // Browse pointer
  1846.                    )
  1847.  
  1848.    IF nSens <> NIL
  1849.  
  1850.       IF nSens == 0          // Move the pointer
  1851.  
  1852.                              // Set the position depending on %
  1853.                              // MAX and MIN prevent overriding browse bounds
  1854.          oBrowse:ColPos := INT(MIN(oBrowse:ColCount,MAX(oBrowse:freeze,oBrowse:freeze+nPercent*(oBrowse:colCount-oBrowse:freeze))))
  1855.  
  1856.       ELSEIF nSens==1        // Move right
  1857.  
  1858.          IF oBrowse:ColPos <  oBrowse:ColCount
  1859.             oBrowse:ColPos := oBrowse:ColPos + 1
  1860.          ENDIF
  1861.  
  1862.       ELSEIF nSens==-1       // Move left
  1863.  
  1864.          IF oBrowse:ColPos >  oBrowse:Freeze
  1865.             oBrowse:ColPos := oBrowse:ColPos - 1
  1866.          ENDIF
  1867.  
  1868.       ENDIF
  1869.  
  1870.    ELSE                      // nSens==NIL mean : what is location in %
  1871.  
  1872.    ENDIF
  1873.  
  1874.                              // If ColPos==1, % ==0
  1875.                              // Else dont forget freeze
  1876.    RETURN (IF(oBrowse:ColPos==1,0,(oBrowse:ColPos-oBrowse:freeze)/(oBrowse:colCount-oBrowse:freeze)))
  1877.  
  1878. *
  1879. FUNCTION BrowseClic(nMouseX  ,;    // X Mouse location
  1880.                     nMouseY  ,;    // Y Mouse location
  1881.                     oBrowse  ,;    // Browse pointer
  1882.                     nTopLines ;    // Number of top line (heading, headsep)
  1883.                    )
  1884.  
  1885.    LOCAL nHitCol   := INT(nMouseX/FONT_SIZE_X)
  1886.    LOCAL nHitRow   := INT(nMouseY/FONT_SIZE_Y)
  1887.    LOCAL lPosFound := .F.
  1888.    LOCAL nOldCol   := 0
  1889.    LOCAL nNewCol   := 0
  1890.    LOCAL nI        := 0
  1891.  
  1892.  
  1893.    IF nTopLines == NIL
  1894.                              // Assume heading is only one line and
  1895.                              // headsep is also one line
  1896.       nTopLines := 2
  1897.    ENDIF
  1898.  
  1899.  
  1900.    mHide()                   // Show mouse
  1901.  
  1902.                              // Find col pointed by mouse
  1903.                              // Use COL() with CURSOR ON to find column
  1904.                              // locations on the tbrowse screen
  1905.    SET CURSOR ON
  1906.                              // Goto left visible column
  1907.    oBrowse:Home()
  1908.                              // Scan all visible column
  1909.    FOR nI := oBrowse:leftVisible TO oBrowse:RightVisible-1
  1910.  
  1911.       oBrowse:Right()
  1912.       oBrowse:forceStable()
  1913.       nNewCol:=COL()
  1914.  
  1915.       IF nOldCol<=nHitCol .AND. nHitCol<nNewCol
  1916.  
  1917.          lPosFound      := .T.
  1918.          oBrowse:colPos := nI
  1919.  
  1920.          EXIT                // Clic column found, EXIT FOR/NEXT
  1921.  
  1922.       ENDIF
  1923.  
  1924.       nOldCol := nNewCol
  1925.  
  1926.    NEXT nI
  1927.  
  1928.    SET CURSOR OFF            // Turn cursor OFF
  1929.  
  1930.    IF !lPosFound             // Not found --> Column probably freezed
  1931.        oBrowse:colPos := oBrowse:RightVisible
  1932.    ENDIF
  1933.  
  1934.                              // Find row pointed by mouse
  1935.    oBrowse:rowpos := nHitRow-(oBrowse:nTop+nTopLines)+1
  1936.  
  1937.                              // Resfresh and stabilize
  1938.    oBrowse:refreshall()
  1939.    oBrowse:forceStable()
  1940.  
  1941.    mShow()                   // Show mouse
  1942.  
  1943.  
  1944.    RETURN (NIL)
  1945.  
  1946.  
  1947. *
  1948.                              // Group Message Box
  1949.                              // Note : Here are some very simples
  1950.                              // CA-CLIPPER generics functions,
  1951.                              // to allow use of message boxes
  1952. /***
  1953. *
  1954. *  nMessageBox()        Draw a modal message box
  1955. *                       the user choose the mode.
  1956. *
  1957. */
  1958. *
  1959. FUNCTION nMessageBox(cMessage  ,; // Message string
  1960.                      cTitle    ,; // Box title
  1961.                      xOptions  ,; // Option : An array of string or one MB_ define
  1962.                      xIcon      ; // Icon to be displayed MB_ICON_QUESTION /.._EXCLAMATION /.._STOP /.._INFO
  1963.                     )
  1964.  
  1965.    LOCAL aOptions       := {}     // Array of options
  1966.  
  1967.    LOCAL nTop           := 0      // Top of box
  1968.    LOCAL nLeft          := 0      // Left of box
  1969.  
  1970.    LOCAL nHeight        := 0      // Box height
  1971.    LOCAL nWidth         := 0      // Box width
  1972.  
  1973.    LOCAL nI             := 0      // Loop variable
  1974.    LOCAL nJ             := 0      // Loop variable
  1975.    LOCAL nKey           := 0      // Keyboard inkey value
  1976.  
  1977.    LOCAL nOptLeft       := 0      // Options left position
  1978.    LOCAL nOptLen        := 0      // Options len of display
  1979.    LOCAL nButLen        := 0      // Len of buttons
  1980.  
  1981.    LOCAL aMessage       := {}     // Message Array
  1982.    LOCAL nMessLen       := 0      // Max message len
  1983.  
  1984.    LOCAL nSaveRow       := ROW()  // Save screen state
  1985.    LOCAL nSaveCol       := COL()
  1986.    LOCAL nSaveCur       := SETCURSOR()
  1987.    LOCAL xSaveScr       := NIL
  1988.  
  1989.    LOCAL aWinButtons    := {}     // Buttons Handler
  1990.  
  1991.    LOCAL lExitAllowed   := .F.    // Main loop controler
  1992.  
  1993.    SETCURSOR(0)
  1994.  
  1995.    nMessLen := 0             // Max message len
  1996.    IF VALTYPE(cMessage)<>"C"
  1997.                              // If message undefined, default to ""
  1998.       aMessage := {""}
  1999.  
  2000.    ELSE
  2001.                              // Use ; to force message to be splited
  2002.       DO WHILE LEN(cMessage)>0
  2003.  
  2004.          IF (nI:=AT(';',cMessage))==0
  2005.                              // Store messages in aMessage
  2006.             AADD(aMessage,cMessage)
  2007.             cMessage := ''
  2008.          ELSE
  2009.             AADD(aMessage,LEFT(cMessage,nI-1))
  2010.             cMessage := RIGHT(cMessage,LEN(cMessage)-nI)
  2011.          ENDIF
  2012.  
  2013.          nMessLen := MAX(nMessLen,LEN(ATAIL(aMessage)))
  2014.  
  2015.       ENDDO
  2016.    ENDIF
  2017.  
  2018.                              // If title undefined, default to ""
  2019.    IF VALTYPE(cTitle)<>"C"
  2020.       cTitle := ""
  2021.    ENDIF
  2022.                              // Compute MB_ buttons options
  2023.    IF VALTYPE(xOptions)=="N"
  2024.  
  2025.       IF xOptions==MB_OK
  2026.  
  2027.          aOptions := {"Ok"}
  2028.  
  2029.       ELSEIF xOptions==MB_OK_CANCEL
  2030.  
  2031.          aOptions := {"Ok","Cancel"}
  2032.  
  2033.       ELSEIF xOptions==MB_ABORT_RETRY_IGNORE
  2034.  
  2035.          aOptions := {"Abort","Retry","Ignore"}
  2036.  
  2037.       ELSEIF xOptions==MB_YES_NO_CANCEL
  2038.  
  2039.          aOptions := {"Yes","No","Cancel"}
  2040.  
  2041.       ELSEIF xOptions==MB_YES_NO
  2042.  
  2043.          aOptions := {"Yes","No"}
  2044.  
  2045.       ELSEIF xOptions==MB_RETRY_CANCEL
  2046.  
  2047.          aOptions := {"Retry","Cancel"}
  2048.  
  2049.       ENDIF
  2050.  
  2051.    ELSEIF VALTYPE(xOptions)=="A"
  2052.                              // An array of string is passed, use it as options
  2053.       aOptions := xOptions
  2054.  
  2055.    ELSE                      // Default to Ok
  2056.  
  2057.       aOptions := {"Ok"}
  2058.  
  2059.    ENDIF
  2060.  
  2061.  
  2062.    nButLen := 0              // Determine max width of buttons
  2063.    FOR nI := 1 TO LEN(aOptions)
  2064.        nButLen := MAX(nButLen,LEN(aOptions[nI]))
  2065.    NEXT
  2066.  
  2067.                              // Resize all buttons
  2068.    FOR nI := 1 TO LEN(aOptions)
  2069.         aOptions[nI] := PADC(aOptions[nI],nButLen)
  2070.    NEXT
  2071.  
  2072.                              // Compute len of options to display
  2073.    nOptLen := LEN(aOptions)*(nButLen+2)
  2074.  
  2075.  
  2076.                              // Compute box position
  2077.    nWidth   := MAX(nMessLen,nOptLen)+6+2+2+1
  2078.    nHeight  := 2+4+LEN(aMessage)
  2079.  
  2080.    nTop     := INT((MAXROW()+1-nHeight)/2)
  2081.    nLeft    := INT((MAXCOL()+1-nWidth)/2)
  2082.  
  2083.    nOptLeft := INT((MAXCOL()+1-nOptLen)/2)+3
  2084.  
  2085.                              // Save screen under box
  2086.    xSaveScr := SAVESCREEN(nTop,nLeft,nTop+nHeight,nLeft+nWidth)
  2087.  
  2088.                              // display 3D box
  2089.    DISPBOX(nTop,nLeft,nTop+nHeight,nLeft+nWidth,LLG_BOX_GRAY_SQUARE)
  2090.  
  2091.                              // display Icon
  2092.    IF xIcon<>NIL
  2093.  
  2094.       IF xIcon ==MB_ICON_QUESTION
  2095.  
  2096.          gBmpDisp(gBmpLoad("DIA_QUES.BMP") , (nLeft+4)*FONT_SIZE_X , (nTop+2)*FONT_SIZE_Y )
  2097.  
  2098.       ELSEIF xIcon ==MB_ICON_EXCLAMATION
  2099.  
  2100.          gBmpDisp(gBmpLoad("DIA_EXCL.BMP") , (nLeft+4)*FONT_SIZE_X , (nTop+2)*FONT_SIZE_Y )
  2101.  
  2102.       ELSEIF xIcon ==MB_ICON_STOP
  2103.  
  2104.          gBmpDisp(gBmpLoad("DIA_STOP.BMP") , (nLeft+4)*FONT_SIZE_X , (nTop+2)*FONT_SIZE_Y )
  2105.  
  2106.       ELSEIF xIcon ==MB_ICON_INFO
  2107.  
  2108.          gBmpDisp(gBmpLoad("DIA_INFO.BMP") , (nLeft+4)*FONT_SIZE_X , (nTop+2)*FONT_SIZE_Y )
  2109.  
  2110.       ENDIF
  2111.  
  2112.    ENDIF
  2113.  
  2114.                              // display Title
  2115.    IF VALTYPE(cTitle)=='C'
  2116.  
  2117.       gWriteAt( ( nLeft+INT((nWidth-LEN(cTitle))/2 ))* FONT_SIZE_X ,;
  2118.                 nTop * FONT_SIZE_Y                                 ,;
  2119.                 cTitle                                             ,;
  2120.                 1                                                  ,;
  2121.                 LLG_MODE_SET                                        ;
  2122.               )
  2123.  
  2124.    ENDIF
  2125.  
  2126.  
  2127.                              // Display message
  2128.    FOR nI := 1 TO LEN(aMessage)
  2129.        DEVPOS( nTop+1+nI, nLeft + 6 + INT( (nWidth-4-LEN(aMessage[nI]) ) /2 ) )
  2130.        DEVOUT(aMessage[nI],"N/W+")
  2131.    NEXT
  2132.  
  2133.  
  2134.                              // Compute each option location and create a button
  2135.    nJ := nOptLeft + 1
  2136.    FOR nI := 1 TO LEN(aOptions)
  2137.  
  2138.        @ nJ * FONT_SIZE_X                        ,;
  2139.          (nTop+nHeight-2)  * FONT_SIZE_Y        ,,;
  2140.          BUTTON                                   ;
  2141.          STYLE BUTTON_TYPE_KEY                    ;
  2142.          ACTION nI                                ;
  2143.          ACCELERATOR LEFT(LTRIM(aOptions[nI]),1)  ;
  2144.          DISPLAYUP   aOptions[nI]                 ;
  2145.          ATTACH aWinButtons
  2146.  
  2147.        nJ += LEN(aOptions[nI])+2
  2148.  
  2149.    NEXT
  2150.                              // Show all buttons
  2151.    SHOW ALL BUTTONS aWinButtons
  2152.  
  2153.  
  2154.    DO WHILE !lExitAllowed    // Loop while not exit requested
  2155.  
  2156.                              // Use mInkey() to manage buttons
  2157.       nKey := mInkey(0,aWinButtons)
  2158.                              // Each button return a pseudo key from 1 to LEN(aOptions)
  2159.       IF nKey>=1 .AND. nKey<=LEN(aOptions)
  2160.  
  2161.          lExitAllowed := .T.
  2162.  
  2163.       ENDIF
  2164.  
  2165.    ENDDO
  2166.  
  2167.                              // Restore environnement values
  2168.    mHide()
  2169.    RESTSCREEN(nTop,nLeft,nTop+nHeight,nLeft+nWidth,xSaveScr)
  2170.    DEVPOS(nSaveRow,nSaveCol)
  2171.    SETCURSOR(nSaveCur)
  2172.  
  2173.    RETURN (nKey)
  2174.  
  2175.  
  2176. *
  2177.                              // Group Video Modes
  2178.                              // Note : Here are some very simples
  2179.                              // CA-CLIPPER generics functions,
  2180.                              // to allow yo to manages video modes
  2181. /***
  2182. *
  2183. *
  2184. *  WallPaper()          Recover all the screen with a .BMP file
  2185. *  nSetBestVideo()      Look for the best video mode available in 16 or 256 colors
  2186. *  aVideoModes()        Grab all the video modes availables in 16 and 256 colors
  2187. *  nChooseVideoMode()   Grab all available video modes in VGA and VESA and lets
  2188. *                       the user choose the mode.
  2189. *
  2190. */
  2191.  
  2192. *
  2193. FUNCTION WallPaper(cFileName)
  2194.                              // This function load the cFileName .BMP
  2195.                              // file and recover all the screen
  2196.  
  2197.                              // Get maximum graphics coordinates
  2198.    LOCAL nNeedX  := gMode()[LLG_MODE_GRAPH_COL]
  2199.    LOCAL nNeedY  := gMode()[LLG_MODE_GRAPH_ROW]
  2200.  
  2201.                              // Create a .BMP pointer
  2202.    LOCAL aBmp    := {}
  2203.                              // Indices
  2204.    LOCAL nPaintX := 0
  2205.    LOCAL nPaintY := 0
  2206.  
  2207.    IF cFileName==NIL         // Default to Marble.Bmp
  2208.       cFileName := 'MARBLE.BMP'
  2209.    ENDIF
  2210.  
  2211.                              // Load the defined filename
  2212.    aBmp := gBmpLoad(cFileName)
  2213.  
  2214.  
  2215.    IF !EMPTY(aBmp)
  2216.                              // If BMP have been loaded succesfully
  2217.  
  2218.        DO WHILE nPaintY <= nNeedY
  2219.                              // While vertical filling not completed
  2220.  
  2221.           DO WHILE nPaintX <= nNeedX
  2222.                              // While horizontal filling not completed
  2223.  
  2224.                              // Display BMP
  2225.              gBmpDisp(aBmp,nPaintX,nPaintY)
  2226.  
  2227.                              // Move X coordinate by the length of .BMP
  2228.              nPaintX += aBmp[LLG_BMP_X]
  2229.  
  2230.           ENDDO
  2231.  
  2232.                              // Reset X coordinate
  2233.           nPaintX := 0
  2234.                              // Move Y coordinate by the height of .BMP
  2235.           nPaintY += aBmp[LLG_BMP_Y]
  2236.  
  2237.        ENDDO
  2238.  
  2239.    ENDIF
  2240.  
  2241.  
  2242.    RETURN (NIL)
  2243.  
  2244.  
  2245. *
  2246. FUNCTION nSetBestVideo(nVideoParam ;  // LLG_VIDEO_BEST_16 | LLG_VIDEO_BEST_256
  2247.                       )
  2248.                              // This function look for the best video mode
  2249.                              // available in 16 or 256 colors
  2250.  
  2251.    LOCAL nBestMode := 0      // If no mode available, return 0
  2252.  
  2253.  
  2254.    IF nVideoParam == LLG_VIDEO_BEST_16
  2255.  
  2256.                              // Check if 1280_1024_16 is supported
  2257.       IF VALTYPE(gMode(-LLG_VIDEO_VESA_1280_1024_16))=='A'
  2258.  
  2259.          nBestMode := LLG_VIDEO_VESA_1280_1024_16
  2260.  
  2261.       ELSE
  2262.  
  2263.                              // Check if 1024_768_16 is supported
  2264.          IF VALTYPE(gMode(-LLG_VIDEO_VESA_1024_768_16))=='A'
  2265.  
  2266.             nBestMode := LLG_VIDEO_VESA_1024_768_16
  2267.  
  2268.          ELSE
  2269.  
  2270.                              // Check if 800_592_16 is supported
  2271.             IF VALTYPE(gMode(-LLG_VIDEO_VESA_800_592_16))=='A'
  2272.  
  2273.                nBestMode := LLG_VIDEO_VESA_800_592_16
  2274.  
  2275.             ELSE
  2276.  
  2277.                              // Check if 640_480_16 is supported
  2278.                IF VALTYPE(gMode(-LLG_VIDEO_VGA_640_480_16))
  2279.  
  2280.                   nBestMode := LLG_VIDEO_VGA_640_480_16
  2281.  
  2282.                ENDIF
  2283.  
  2284.             ENDIF
  2285.  
  2286.          ENDIF
  2287.  
  2288.       ENDIF
  2289.  
  2290.  
  2291.    ELSEIF nVideoParam == LLG_VIDEO_BEST_256
  2292.  
  2293.  
  2294.                              // Check if 1280_1024_256 is supported
  2295.       IF VALTYPE(gMode(-LLG_VIDEO_VESA_1280_1024_256))=='A'
  2296.  
  2297.          nBestMode := LLG_VIDEO_VESA_1280_1024_256
  2298.  
  2299.       ELSE
  2300.  
  2301.                              // Check if 1024_768_256 is supported
  2302.          IF VALTYPE(-gMode(LLG_VIDEO_VESA_1024_768_256))=='A'
  2303.  
  2304.             nBestMode := LLG_VIDEO_VESA_1024_768_256
  2305.  
  2306.          ELSE
  2307.  
  2308.                              // Check if 800_592_256 is supported
  2309.             IF VALTYPE(gMode(-LLG_VIDEO_VESA_800_592_256))=='A'
  2310.  
  2311.                nBestMode := LLG_VIDEO_VESA_800_592_256
  2312.  
  2313.             ELSE
  2314.  
  2315.                              // Check if 640_480_256 is supported
  2316.                IF VALTYPE(gMode(-LLG_VIDEO_VESA_640_480_256))=='A'
  2317.  
  2318.                   nBestMode := LLG_VIDEO_VESA_640_480_256
  2319.  
  2320.                ENDIF
  2321.  
  2322.             ENDIF
  2323.  
  2324.          ENDIF
  2325.  
  2326.       ENDIF
  2327.  
  2328.    ENDIF
  2329.  
  2330.    RETURN (nBestMode)
  2331.  
  2332.  
  2333.  
  2334. *
  2335. FUNCTION aVideoModes()
  2336.                              // This function grab all the video modes
  2337.                              // availables in 16 and 256 colors
  2338.  
  2339.    LOCAL aVideoMode  := {}
  2340.  
  2341.                              // Check if 640_480_16 is supported
  2342.    IF VALTYPE(gMode(-LLG_VIDEO_VGA_640_480_16))=='A'
  2343.  
  2344.       AADD(aVideoMode,LLG_VIDEO_VGA_640_480_16)
  2345.  
  2346.    ENDIF
  2347.                              // Check if 800_592_16 is supported
  2348.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_800_592_16))=='A'
  2349.  
  2350.       AADD(aVideoMode,LLG_VIDEO_VESA_800_592_16)
  2351.  
  2352.    ENDIF
  2353.                              // Check if 1024_768_16 is supported
  2354.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_1024_768_16))=='A'
  2355.  
  2356.       AADD(aVideoMode,LLG_VIDEO_VESA_1024_768_16)
  2357.  
  2358.    ENDIF
  2359.                              // Check if 1280_1024_16 is supported
  2360.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_1280_1024_16))=='A'
  2361.  
  2362.       AADD(aVideoMode,LLG_VIDEO_VESA_1280_1024_16)
  2363.  
  2364.    ENDIF
  2365.  
  2366.                              // Check if 640_480_256 is supported
  2367.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_640_480_256))=='A'
  2368.  
  2369.        AADD(aVideoMode,LLG_VIDEO_VESA_640_480_256)
  2370.  
  2371.    ENDIF
  2372.                              // Check if 800_592_256 is supported
  2373.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_800_592_256))=='A'
  2374.  
  2375.       AADD(aVideoMode,LLG_VIDEO_VESA_800_592_256)
  2376.  
  2377.    ENDIF
  2378.                              // Check if 1024_768_256 is supported
  2379.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_1024_768_256))=='A'
  2380.  
  2381.       AADD(aVideoMode,LLG_VIDEO_VESA_1024_768_256)
  2382.  
  2383.    ENDIF
  2384.                              // Check if 1280_1024_256 is supported
  2385.    IF VALTYPE(gMode(-LLG_VIDEO_VESA_1280_1024_256))=='A'
  2386.  
  2387.       AADD(aVideoMode,LLG_VIDEO_VESA_1280_1024_256)
  2388.  
  2389.    ENDIF
  2390.  
  2391.  
  2392.    RETURN (aVideoMode)
  2393.  
  2394.  
  2395. *
  2396. FUNCTION nChooseVideoMode()
  2397.                              // This function use aVideoModes() to checks for
  2398.                              // all available video modes in VGA and VESA and
  2399.                              // lets the user choose the mode.
  2400.  
  2401.                              // This function does not set the mode the user
  2402.                              // choose
  2403.  
  2404.                              // It returns the value of the mode or 0 to abort
  2405.  
  2406.    LOCAL nI := 0
  2407.    LOCAL aI := {}
  2408.  
  2409.    LOCAL aA := {}
  2410.    LOCAL cA := ""
  2411.  
  2412.    LOCAL aJ := { { LLG_VIDEO_VGA_640_480_16     , "  640 x  480 x  16" } ,;
  2413.                  { LLG_VIDEO_VESA_800_592_16    , "  800 x  592 x  16" } ,;
  2414.                  { LLG_VIDEO_VESA_1024_768_16   , " 1024 x  768 x  16" } ,;
  2415.                  { LLG_VIDEO_VESA_1280_1024_16  , " 1280 x 1024 x  16" } ,;
  2416.                  { LLG_VIDEO_VESA_640_480_256   , "  640 x  480 x 256" } ,;
  2417.                  { LLG_VIDEO_VESA_800_592_256   , "  800 x  592 x 256" } ,;
  2418.                  { LLG_VIDEO_VESA_1024_768_256  , " 1024 x  768 x 256" } ,;
  2419.                  { LLG_VIDEO_VESA_1280_1024_256 , " 1280 x 1024 x 256" } ,;
  2420.                }
  2421.  
  2422.  
  2423.    aI := aVideoModes()       // Collect video modes
  2424.  
  2425.    IF LEN(aI)==0             // No graphics modes availables
  2426.  
  2427.       nI := 0
  2428.  
  2429.    ELSEIF LEN(aI)==1         // Only one graphics mode available, dont need
  2430.                              // to alert the user
  2431.       nI := aI[1]
  2432.  
  2433.    ELSE                      // More than one video mode available
  2434.  
  2435.                              // Construct an alert box
  2436.       FOR nI := 1 TO LEN(aI)
  2437.           cA += CHR(64+nI)+" : "+aJ[ASCAN(aJ,{|el| el[1]==aI[nI] }),2]+";"
  2438.           AADD(aA,CHR(64+nI))
  2439.       NEXT nI
  2440.  
  2441.       nI:=ALERT(cA,aA)       // Display alert box
  2442.  
  2443.       IF nI<>0               // If user does not abort, retrieve mode from aI
  2444.          nI := aI[nI]
  2445.       ENDIF
  2446.  
  2447.    ENDIF
  2448.  
  2449.    RETURN (nI)
  2450.  
  2451. *
  2452.                              // Group Palette
  2453.                              // Note : Here are some very simples
  2454.                              // functions to allow palette and colors manipulations
  2455.                              // You should use or modify them if needed
  2456. /***
  2457. *
  2458. *
  2459. *  ChgPalette()         Change the colors palette
  2460. *  nUsedColor()         Color being changed
  2461. *  nChangeColor()       Change the components of a color
  2462. *  ButPalColor()        Draw a color button
  2463. *  aPalSave()           Save components of all colors
  2464. *  aPalRest()           Rest components of all colors
  2465. *
  2466. */
  2467.  
  2468. *
  2469. FUNCTION ChgPalette()
  2470.                              // Change the colors palette
  2471.  
  2472.    LOCAL nTop        :=  8   // Windows coordinates
  2473.    LOCAL nLeft       :=  8
  2474.    LOCAL nBottom     := 18
  2475.    LOCAL nRight      := 75
  2476.  
  2477.                              // Old palette values to allow cancel
  2478.                              // Note we work on the first 16 colors
  2479.    LOCAL aOldPalette := aPalSave(16)
  2480.  
  2481.                              // Save
  2482.    LOCAL xSave       := SAVESCREEN(nTop,nLeft,nBottom,nRight)
  2483.  
  2484.    LOCAL aWinButtons := {}   // Buttons handle
  2485.    LOCAL nKey        :=  0   // Key handle
  2486.                              // Potentiometers handle
  2487.    LOCAL aPalPoten   := {{},{},{}}
  2488.  
  2489.                              // Block to EVAL when a component of a color
  2490.                              // is changed
  2491.    LOCAL bPalBlock   := { || gSetPal(nUsedColor(),nPotRed,nPotGre,nPotBlu) }
  2492.  
  2493.                              // Display a 3D box
  2494.    DISPBOX(nTop,nLeft,nBottom,nRight,LLG_BOX_GRAY_SQUARE)
  2495.  
  2496.                              // Add a potentiometer to manage Red %
  2497.    @ nLeft+4,nTop+2 WIDTH 25                                     ;
  2498.      POTENTIOMETER                                               ;
  2499.      SETGET { |nVal| IF(nVal==NIL,nPotRed,nPotRed:=nVal)  }      ;
  2500.      EXECUTE bPalBlock                                           ;
  2501.      RANGE 0,63                                                  ;
  2502.      PICTURE "999"                                               ;
  2503.      HANDLE aPalPoten[1]                                         ;
  2504.      ATTACH aWinButtons
  2505.  
  2506.                              // Add a potentiometer to manage Green %
  2507.    @ nLeft+4,nTop+4 WIDTH 25                                     ;
  2508.      POTENTIOMETER                                               ;
  2509.      SETGET { |nVal| IF(nVal==NIL,nPotGre,nPotGre:=nVal)  }      ;
  2510.      EXECUTE bPalBlock                                           ;
  2511.      RANGE 0,63                                                  ;
  2512.      PICTURE "999"                                               ;
  2513.      HANDLE aPalPoten[2]                                         ;
  2514.      ATTACH aWinButtons
  2515.  
  2516.                              // Add a potentiometer to manage Blue %
  2517.    @ nLeft+4,nTop+6 WIDTH 25                                     ;
  2518.      POTENTIOMETER                                               ;
  2519.      SETGET { |nVal| IF(nVal==NIL,nPotBlu,nPotBlu:=nVal)  }      ;
  2520.      EXECUTE bPalBlock                                           ;
  2521.      RANGE 0,63                                                  ;
  2522.      PICTURE "999"                                               ;
  2523.      HANDLE aPalPoten[3]                                         ;
  2524.      ATTACH aWinButtons
  2525.  
  2526.  
  2527.                              // Add a button for color 00
  2528.    @ FONT_SIZE_X*(nLeft+02)                                                         ,;
  2529.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2530.      FONT_SIZE_X*(nLeft+06)-1                                                       ,;
  2531.      FONT_SIZE_Y*nBottom-1                                                           ;
  2532.      BUTTON                                                                          ;
  2533.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2534.      ACTION { || nUsedColor(nChangeColor(00,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2535.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,00,.T.) }                     ;
  2536.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,00,.F.) }                     ;
  2537.      ATTACH aWinButtons
  2538.  
  2539.                              // Add a button for color 01
  2540.    @ FONT_SIZE_X*(nLeft+06)                                                         ,;
  2541.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2542.      FONT_SIZE_X*(nLeft+10)-1                                                       ,;
  2543.      FONT_SIZE_Y*nBottom-1                                                           ;
  2544.      BUTTON                                                                          ;
  2545.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2546.      ACTION { || nUsedColor(nChangeColor(01,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2547.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,01,.T.) }                     ;
  2548.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,01,.F.) }                     ;
  2549.      ATTACH aWinButtons
  2550.  
  2551.                              // Add a button for color 02
  2552.    @ FONT_SIZE_X*(nLeft+10)                                                         ,;
  2553.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2554.      FONT_SIZE_X*(nLeft+14)-1                                                       ,;
  2555.      FONT_SIZE_Y*nBottom-1                                                           ;
  2556.      BUTTON                                                                          ;
  2557.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2558.      ACTION { || nUsedColor(nChangeColor(02,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2559.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,02,.T.) }                     ;
  2560.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,02,.F.) }                     ;
  2561.      ATTACH aWinButtons
  2562.  
  2563.                              // Add a button for color 03
  2564.    @ FONT_SIZE_X*(nLeft+14)                                                         ,;
  2565.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2566.      FONT_SIZE_X*(nLeft+18)-1                                                       ,;
  2567.      FONT_SIZE_Y*nBottom-1                                                           ;
  2568.      BUTTON                                                                          ;
  2569.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2570.      ACTION { || nUsedColor(nChangeColor(03,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2571.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,03,.T.) }                     ;
  2572.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,03,.F.) }                     ;
  2573.      ATTACH aWinButtons
  2574.  
  2575.                              // Add a button for color 04
  2576.    @ FONT_SIZE_X*(nLeft+18)                                                         ,;
  2577.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2578.      FONT_SIZE_X*(nLeft+22)-1                                                       ,;
  2579.      FONT_SIZE_Y*nBottom-1                                                           ;
  2580.      BUTTON                                                                          ;
  2581.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2582.      ACTION { || nUsedColor(nChangeColor(04,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2583.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,04,.T.) }                     ;
  2584.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,04,.F.) }                     ;
  2585.      ATTACH aWinButtons
  2586.  
  2587.                              // Add a button for color 05
  2588.    @ FONT_SIZE_X*(nLeft+22)                                                         ,;
  2589.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2590.      FONT_SIZE_X*(nLeft+26)-1                                                       ,;
  2591.      FONT_SIZE_Y*nBottom-1                                                           ;
  2592.      BUTTON                                                                          ;
  2593.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2594.      ACTION { || nUsedColor(nChangeColor(05,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2595.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,05,.T.) }                     ;
  2596.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,05,.F.) }                     ;
  2597.      ATTACH aWinButtons
  2598.  
  2599.                              // Add a button for color 06
  2600.    @ FONT_SIZE_X*(nLeft+26)                                                         ,;
  2601.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2602.      FONT_SIZE_X*(nLeft+30)-1                                                       ,;
  2603.      FONT_SIZE_Y*nBottom-1                                                           ;
  2604.      BUTTON                                                                          ;
  2605.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2606.      ACTION { || nUsedColor(nChangeColor(06,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2607.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,06,.T.) }                     ;
  2608.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,06,.F.) }                     ;
  2609.      ATTACH aWinButtons
  2610.  
  2611.                              // Add a button for color 07
  2612.    @ FONT_SIZE_X*(nLeft+30)                                                         ,;
  2613.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2614.      FONT_SIZE_X*(nLeft+34)-1                                                       ,;
  2615.      FONT_SIZE_Y*nBottom-1                                                           ;
  2616.      BUTTON                                                                          ;
  2617.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2618.      ACTION { || nUsedColor(nChangeColor(07,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2619.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,07,.T.) }                     ;
  2620.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,07,.F.) }                     ;
  2621.      ATTACH aWinButtons
  2622.  
  2623.                              // Add a button for color 08
  2624.    @ FONT_SIZE_X*(nLeft+34)                                                         ,;
  2625.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2626.      FONT_SIZE_X*(nLeft+38)-1                                                       ,;
  2627.      FONT_SIZE_Y*nBottom-1                                                           ;
  2628.      BUTTON                                                                          ;
  2629.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2630.      ACTION { || nUsedColor(nChangeColor(08,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2631.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,08,.T.) }                     ;
  2632.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,08,.F.) }                     ;
  2633.      ATTACH aWinButtons
  2634.  
  2635.                              // Add a button for color 09
  2636.    @ FONT_SIZE_X*(nLeft+38)                                                         ,;
  2637.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2638.      FONT_SIZE_X*(nLeft+42)-1                                                       ,;
  2639.      FONT_SIZE_Y*nBottom-1                                                           ;
  2640.      BUTTON                                                                          ;
  2641.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2642.      ACTION { || nUsedColor(nChangeColor(09,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2643.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,09,.T.) }                     ;
  2644.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,09,.F.) }                     ;
  2645.      ATTACH aWinButtons
  2646.  
  2647.                              // Add a button for color 10
  2648.    @ FONT_SIZE_X*(nLeft+42)                                                         ,;
  2649.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2650.      FONT_SIZE_X*(nLeft+46)-1                                                       ,;
  2651.      FONT_SIZE_Y*nBottom-1                                                           ;
  2652.      BUTTON                                                                          ;
  2653.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2654.      ACTION { || nUsedColor(nChangeColor(10,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2655.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,10,.T.) }                     ;
  2656.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,10,.F.) }                     ;
  2657.      ATTACH aWinButtons
  2658.  
  2659.                              // Add a button for color 11
  2660.    @ FONT_SIZE_X*(nLeft+46)                                                         ,;
  2661.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2662.      FONT_SIZE_X*(nLeft+50)-1                                                       ,;
  2663.      FONT_SIZE_Y*nBottom-1                                                           ;
  2664.      BUTTON                                                                          ;
  2665.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2666.      ACTION { || nUsedColor(nChangeColor(11,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2667.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,11,.T.) }                     ;
  2668.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,11,.F.) }                     ;
  2669.      ATTACH aWinButtons
  2670.  
  2671.                              // Add a button for color 12
  2672.    @ FONT_SIZE_X*(nLeft+50)                                                         ,;
  2673.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2674.      FONT_SIZE_X*(nLeft+54)-1                                                       ,;
  2675.      FONT_SIZE_Y*nBottom-1                                                           ;
  2676.      BUTTON                                                                          ;
  2677.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2678.      ACTION { || nUsedColor(nChangeColor(12,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2679.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,12,.T.) }                     ;
  2680.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,12,.F.) }                     ;
  2681.      ATTACH aWinButtons
  2682.  
  2683.                              // Add a button for color 13
  2684.    @ FONT_SIZE_X*(nLeft+54)                                                         ,;
  2685.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2686.      FONT_SIZE_X*(nLeft+58)-1                                                       ,;
  2687.      FONT_SIZE_Y*nBottom-1                                                           ;
  2688.      BUTTON                                                                          ;
  2689.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2690.      ACTION { || nUsedColor(nChangeColor(13,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2691.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,13,.T.) }                     ;
  2692.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,13,.F.) }                     ;
  2693.      ATTACH aWinButtons
  2694.  
  2695.                              // Add a button for color 14
  2696.    @ FONT_SIZE_X*(nLeft+58)                                                         ,;
  2697.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2698.      FONT_SIZE_X*(nLeft+62)-1                                                       ,;
  2699.      FONT_SIZE_Y*nBottom-1                                                           ;
  2700.      BUTTON                                                                          ;
  2701.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2702.      ACTION { || nUsedColor(nChangeColor(14,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2703.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,14,.T.) }                     ;
  2704.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,14,.F.) }                     ;
  2705.      ATTACH aWinButtons
  2706.  
  2707.                              // Add a button for color 15
  2708.    @ FONT_SIZE_X*(nLeft+62)                                                         ,;
  2709.      FONT_SIZE_Y*(nBottom-2)                                                        ,;
  2710.      FONT_SIZE_X*(nLeft+66)-1                                                       ,;
  2711.      FONT_SIZE_Y*nBottom-1                                                           ;
  2712.      BUTTON                                                                          ;
  2713.      STYLE BUTTON_TYPE_RELEASE                                                       ;
  2714.      ACTION { || nUsedColor(nChangeColor(15,aPalPoten,nLeft,nTop,nRight,nBottom)) }  ;
  2715.      DISPLAYUP { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,15,.T.) }                     ;
  2716.      DISPLAYDN { |nL,nT,nR,nB| ButPalColor(nL,nT,nR,nB,15,.F.) }                     ;
  2717.      ATTACH aWinButtons
  2718.  
  2719.  
  2720.                              // Add a "CANCEL" button to emulate K_ESC
  2721.    @ (nRight - 10) * FONT_SIZE_X             ,;
  2722.      (nTop +  2 ) * FONT_SIZE_Y             ,,;
  2723.      BUTTON                                   ;
  2724.      STYLE BUTTON_TYPE_KEY                    ;
  2725.      ACTION K_ESC                             ;
  2726.      ACCELERATOR K_ALT_L                      ;
  2727.      DISPLAYUP gBmpLoad("CANCEL.BMU")         ;
  2728.      DISPLAYDN gBmpLoad("CANCEL.BMD")         ;
  2729.      ATTACH aWinButtons
  2730.  
  2731.                              // Add a "OK" button to emulate K_PGDN
  2732.    @ (nRight - 10) * FONT_SIZE_X             ,;
  2733.      (nTop +  5 ) * FONT_SIZE_Y             ,,;
  2734.      BUTTON                                   ;
  2735.      STYLE BUTTON_TYPE_KEY                    ;
  2736.      ACTION K_PGDN                            ;
  2737.      ACCELERATOR K_ALT_O                      ;
  2738.      DISPLAYUP gBmpLoad("OK.BMU")             ;
  2739.      DISPLAYDN gBmpLoad("OK.BMD")             ;
  2740.      ATTACH aWinButtons
  2741.  
  2742.                              // Display all buttons
  2743.    ButtonShowAll(aWinButtons)
  2744.  
  2745.                              // Set the default color to 14
  2746.    nUsedColor(nChangeColor(14,aPalPoten,nLeft,nTop,nRight,nBottom))
  2747.  
  2748.    WHILE .T.                 // Repeat until user request EXIT
  2749.  
  2750.                              // Use mInkey() to manage key and buttons
  2751.       nKey := mInkey(0,aWinButtons)
  2752.  
  2753.       DO CASE
  2754.                              // IF Page Down, valid
  2755.          CASE nKey == K_PGDN
  2756.  
  2757.               EXIT
  2758.  
  2759.          CASE nKey == K_ESC
  2760.                              // IF ESC, cancel
  2761.                              // Restore previously saved palette
  2762.               aPalRest(aOldPalette)
  2763.                              // Reset Red/Green/Blue variables
  2764.               nChangeColor(nUsedColor(),aPalPoten,nLeft,nTop,nRight,nBottom)
  2765.               EXIT
  2766.  
  2767.       ENDCASE
  2768.  
  2769.    ENDDO
  2770.  
  2771.                              // Restore old screen
  2772.    RESTSCREEN(nTop,nLeft,nBottom,nRight,xSave)
  2773.  
  2774.    RETURN (NIL)
  2775.  
  2776. *
  2777. STATIC FUNCTION nUsedColor(nColor)
  2778.                              // Set Get function to manage color
  2779.                              // beeing changed
  2780.  
  2781.    STATIC nColorInUse := 0
  2782.  
  2783.    IF nColor<>NIL
  2784.  
  2785.       nColorInUse := nColor
  2786.  
  2787.    ENDIF
  2788.  
  2789.    RETURN (nColorInUse)
  2790.  
  2791.  
  2792. *
  2793. STATIC FUNCTION nChangeColor(nColor    ,;  // Color to be used
  2794.                              aPalPoten ,;  // Handle on potentiometers
  2795.                              nLeft     ,;  // Palette window area
  2796.                              nTop      ,;  //
  2797.                              nRight    ,;  //
  2798.                              nBottom    ;  //
  2799.                             )
  2800.  
  2801.                              // Change the components of a color
  2802.  
  2803.                              // Grab nColor palette components
  2804.    LOCAL aPal := gSetPal(nColor)
  2805.  
  2806.                              // Display a frame
  2807.    gFrame(FONT_SIZE_X*(nRight-37)   ,;
  2808.           FONT_SIZE_Y*(nTop+2)      ,;
  2809.           FONT_SIZE_X*(nRight-11)-1 ,;
  2810.           FONT_SIZE_Y*(nBottom-3)-1 ,;
  2811.           07                        ,;
  2812.           15                        ,;
  2813.           00                        ,;
  2814.           3, 3, 3, 3, LLG_MODE_SET   ;
  2815.          )
  2816.  
  2817.                              // Display the new color
  2818.    gRect(FONT_SIZE_X*(nRight-37)  +3         ,;
  2819.          FONT_SIZE_Y*(nTop+2)     +3         ,;
  2820.          FONT_SIZE_X*(nRight-11)-1-3         ,;
  2821.          FONT_SIZE_Y*(nBottom-3)-1-3         ,;
  2822.          LLG_FILL     ,;
  2823.          nColor       ,;
  2824.          LLG_MODE_SET  ;
  2825.         )
  2826.  
  2827.                              // Reset/redisplay Red/Green/Blue variables
  2828.    EVAL(ATAIL(aPalPoten[1]),nPotRed:=aPal[1])
  2829.    EVAL(ATAIL(aPalPoten[2]),nPotGre:=aPal[2])
  2830.    EVAL(ATAIL(aPalPoten[3]),nPotBlu:=aPal[3])
  2831.  
  2832.                              // Update potentiometers
  2833.    ScrBarUpDate(aPalPoten[1],nPotRed/64)
  2834.    ScrBarUpDate(aPalPoten[2],nPotGre/64)
  2835.    ScrBarUpDate(aPalPoten[3],nPotBlu/64)
  2836.  
  2837.    RETURN (nColor)
  2838.  
  2839.  
  2840. *
  2841. STATIC FUNCTION ButPalColor(nLeft      ,; // Color button coordinates
  2842.                             nTop       ,; //
  2843.                             nRight     ,; //
  2844.                             nBottom    ,; //
  2845.                             nColor     ,; // Color to be displayed
  2846.                             lDisplayUp  ; // Position up or down
  2847.                            )
  2848.  
  2849.                              // Draw a color button
  2850.  
  2851.                              // Display a frame
  2852.    gFrame(nLeft                             ,;
  2853.           nTop                              ,;
  2854.           nRight                            ,;
  2855.           nBottom                           ,;
  2856.           07                                ,;
  2857.           IF(lDisplayUp,00,15)              ,;
  2858.           IF(lDisplayUp,15,00)              ,;
  2859.           3, 3, 3, 3, LLG_MODE_SET           ;
  2860.          )
  2861.  
  2862.                              // Display the color
  2863.    gRect(nLeft+3      ,;
  2864.          nTop+3       ,;
  2865.          nRight-3     ,;
  2866.          nBottom-3    ,;
  2867.          LLG_FILL     ,;
  2868.          nColor       ,;
  2869.          LLG_MODE_SET  ;
  2870.         )
  2871.  
  2872.    RETURN (NIL)
  2873.  
  2874.  
  2875. *
  2876. FUNCTION aPalSave(nFirstColors ;  // Save only the n First Colors
  2877.                  )
  2878.                              // This function save all colors components
  2879.                              // in an array of arrays
  2880.  
  2881.    LOCAL aPalStore := {}
  2882.    LOCAL nI        := 0
  2883.  
  2884.    IF nFirstColors == NIL
  2885.       nFirstColors := gMode()[LLG_MODE_COLOR_MAX]
  2886.    ENDIF
  2887.  
  2888.                              // For all colors requested
  2889.    FOR nI := 1 TO nFirstColors
  2890.  
  2891.                              // Save color reference and color components
  2892.        AADD(aPalStore , { nI-1              ,;
  2893.                           gSetPal(nI-1)[1]  ,;
  2894.                           gSetPal(nI-1)[2]  ,;
  2895.                           gSetPal(nI-1)[3]  ,;
  2896.                         }                    ;
  2897.            )
  2898.  
  2899.    NEXT nI
  2900.                              // Return an array or arrays
  2901.    RETURN (aPalStore)
  2902.  
  2903. *
  2904. FUNCTION aPalRest(aPalette)
  2905.                              // This function set all colors components
  2906.                              // depending on values passed in an array
  2907.  
  2908.    LOCAL nI := 0             // Loop indice
  2909.  
  2910.                              // For all the arrays in the major array
  2911.    FOR nI := 1 TO LEN(aPalette)
  2912.  
  2913.                              // Reset the color components
  2914.        gSetPal(aPalette[nI,1]  ,;
  2915.                aPalette[nI,2]  ,;
  2916.                aPalette[nI,3]  ,;
  2917.                aPalette[nI,4]   ;
  2918.               )
  2919.  
  2920.    NEXT nI
  2921.  
  2922.    RETURN (aPalette)
  2923.  
  2924.  
  2925. *
  2926.                              // Group Business graphic
  2927.                              // Note : Here are some very simples
  2928.                              // CA-CLIPPER generics functions.
  2929.                              // You should use or modify them if needed
  2930. /***
  2931. *
  2932. *  BarGraph()           Display a LINE/LINE_3D/BAR/BAR_3D graph
  2933. *  DrawValue()          Draw values from BarGraph()
  2934. *  CirGraph()           Display a pie graph
  2935. *
  2936. */
  2937.  
  2938. *
  2939. FUNCTION BarGraph( nTop     ,;  // Top coordinates in rows
  2940.                    nleft    ,;  // Left coordinates in columns
  2941.                    nBottom  ,;  // Bottom coordinates in rows
  2942.                    nRight   ,;  // Left coordinates in columns
  2943.                    aValues  ,;  // List of values
  2944.                    nStyle   ,;  // Graph style (STYLE_BAR, STYLE_LINE, STYLE_BAR_3D, STYLE_LINE_3D)
  2945.                    nMin     ,;  // Vertical scale minimum value
  2946.                    nMax      ;  // Vertical scale maximum value
  2947.                  )
  2948.  
  2949.  
  2950.  
  2951.    LOCAL aOldClip     := {}                                // Previous Clipping region
  2952.  
  2953.    LOCAL nI           := 0                                 // Loop pointer
  2954.    LOCAL nJ           := 0                                 // Loop pointer
  2955.    LOCAL nIncrement   := 0                                 // Space beetween each value
  2956.    LOCAL nMaxValue    := 0                                 // Maximum value of data set
  2957.    LOCAL nMinValue    := 0                                 // Minimum value of data set
  2958.    LOCAL nNbBar       := 0                                 // Number of bars for each value
  2959.    Local nBarWidth    := 0                                 // Bar width
  2960.  
  2961.    LOCAL nGraphTop    := (nTop * FONT_SIZE_Y + 20)         // Top   limit of graph area
  2962.    LOCAL nGraphleft   := (nLeft * FONT_SIZE_X + 16 +10 )   // Left     ""
  2963.    LOCAL nGraphBottom := (nBottom * FONT_SIZE_Y - 20)      // Bottom   ""
  2964.    LOCAL nGraphRight  := (nRight * FONT_SIZE_X - 16 -10)   // Right    ""
  2965.  
  2966.    LOCAL nXPosition   := nGraphBottom                     // Position of X axis
  2967.    LOCAL nXAxisColor  := 4                                // Color of X axis
  2968.    LOCAL nYPosition   := nGraphLeft                       // Position of Y axis
  2969.    LOCAL nYAxisColor  := 3                                // Color of Y axis
  2970.  
  2971.    LOCAL nGraphWidth  := nGraphRight - nGraphLeft         // Graph width
  2972.    LOCAL nGraphHeight := nGraphBottom - nGraphTop         // Graph height
  2973.  
  2974.    LOCAL nYlegLen     := 0                                // Length of Y axis legend
  2975.    LOCAL nXLegLen     := 0                                // Total Length of X axis legend
  2976.    LOCAL nXLegNbLine  := 0                                // Number of lines of X axis legend
  2977.  
  2978.  
  2979.  
  2980.                              // Compute Maximum and Minimum values
  2981.    FOR nI := 1 TO LEN(aValues)
  2982.       FOR nJ := 2 TO LEN(aValues[nI])
  2983.          nMaxValue := MAX( aValues[nI,nJ], nMaxValue )
  2984.          nMinValue := MIN( aValues[nI,nJ], nMinValue )
  2985.       NEXT
  2986.                              // Compute maximum number of bars
  2987.       nNbBar := MAX(nNbBar,LEN(aValues[nI])-1)
  2988.  
  2989.                              // Total lentgh of X axis legends
  2990.       nXLegLen := nXLegLen + LEN(aValues[nI,1]) + 1
  2991.  
  2992.    NEXT
  2993.  
  2994.                              // Round minimum and maximum values
  2995.    nMaxValue := nRoundSup(nMaxValue)
  2996.    nMinValue := nRoundSup(nMinValue)
  2997.  
  2998.  
  2999.                              // If maximum and minimum values have been
  3000.                              // defined replace nMinValue and nMaxValue
  3001.    IF nMin <> NIL
  3002.       nMinValue := nMin
  3003.    ENDIF
  3004.    IF nMax <> NIL
  3005.       nMaxValue := nMax
  3006.    ENDIF
  3007.  
  3008.                              // Length of Y axis legend is max of
  3009.                              // minimum value length and maximum value length
  3010.    nYLegLen  := MAX( LEN(ALLTRIM(STR(nMaxValue))), ;
  3011.                      LEN(ALLTRIM(STR(nMinValue))))
  3012.  
  3013.                              // Y axis position
  3014.    nYPosition  := nGraphLeft + nYLegLen * FONT_SIZE_X
  3015.  
  3016.                              // Maximum graph width
  3017.    nGraphWidth := nGraphRight - nYPosition
  3018.  
  3019.                              // Increment to move bars
  3020.    nIncrement  := nGraphWidth / LEN(aValues)
  3021.  
  3022.                              // Bars width
  3023.    nBarWidth   := nIncrement / nNbBar
  3024.  
  3025.                              // Number of X axis legend lines
  3026.    nXLegNbLine  := INT( nXLegLen * FONT_SIZE_X / nGraphWidth )
  3027.    IF nXLegNbLine < nXLegLen * FONT_SIZE_X / nGraphWidth
  3028.       nXLegNbLine  := nXLegNbLine  + 1
  3029.    ENDIF
  3030.                              // Correct graph Height
  3031.    nGraphHeight := nGraphHeight - nXLegNbLine * FONT_SIZE_Y
  3032.  
  3033.                              // Correct graph bottom position
  3034.    nGraphBottom := nGraphBottom - nXLegNbLine * FONT_SIZE_Y
  3035.  
  3036.                              // X axis position
  3037.    nXPosition  := nGraphBottom - ABS( nMinValue / (nMaxValue-nMinValue) ) * nGraphHeight
  3038.  
  3039.                              // Define clipping region to avoid
  3040.                              // writing outside graph
  3041.    aOldClip := gSetClip( nLeft   * FONT_SIZE_X  ,;
  3042.                          nTop    * FONT_SIZE_Y  ,;
  3043.                          nRight  * FONT_SIZE_X  ,;
  3044.                          nBottom * FONT_SIZE_Y   ;
  3045.                        )
  3046.  
  3047.                              // Draw box arround graph
  3048.    gFrame( nLeft   * FONT_SIZE_X     ,;
  3049.            nTop    * FONT_SIZE_Y     ,;
  3050.            nRight  * FONT_SIZE_X - 1 ,;
  3051.            nBottom * FONT_SIZE_Y - 1 ,;
  3052.            7, 15, 8                  ,;
  3053.            5, 5, 5, 5                ,;
  3054.            LLG_MODE_SET               ;
  3055.          )
  3056.  
  3057.                              // Draw horizontal axis
  3058.    gLine( nYPosition         ,;
  3059.           nXPosition         ,;
  3060.           nGraphRight        ,;
  3061.           nXPosition         ,;
  3062.           nXAxisColor        ,;
  3063.           LLG_MODE_SET        ;
  3064.         )
  3065.  
  3066.                              // Draw vertical axis
  3067.    gLine( nYPosition         ,;
  3068.           nGraphTop          ,;
  3069.           nYPosition         ,;
  3070.           nGraphBottom       ,;
  3071.           nYAxisColor        ,;
  3072.           LLG_MODE_SET        ;
  3073.         )
  3074.  
  3075.                              // Place 10 standard values on Y Axis
  3076.    FOR nI := nMinValue TO nMaxValue STEP ABS( (nMinValue-nMaxValue) / 10)
  3077.       gWriteAt( nGraphLeft - FONT_SIZE_X                                                 ,;
  3078.                 nXPosition - nI / ABS( nMinValue - nMaxValue)*nGraphHeight -FONT_SIZE_X  ,;
  3079.                 STR(nI,nYLegLen) + "-"                                                   ,;
  3080.                 nYAxisColor                                                              ,;
  3081.                 LLG_MODE_SET                                                              ;
  3082.               )
  3083.    NEXT nI
  3084.  
  3085.  
  3086.    DrawValue()               // Reset static variables
  3087.                              // keeping previous values
  3088.  
  3089.                              // Draw values
  3090.    FOR nI := 0 TO LEN(aValues) - 1
  3091.  
  3092.                              // Draw bars or a lines for each X value
  3093.       FOR nJ := 0 TO nNbBar-1
  3094.          DrawValue( nYPosition + ( nI * nIncrement ) +                             ;
  3095.                      IF( nStyle == STYLE_BAR .OR. nStyle == STYLE_BAR_3D                  ,;
  3096.                          nJ*nBarWidth                                             ,;
  3097.                          0                                                         ;
  3098.                        )                                                          ,;
  3099.                     nXPosition                                                    ,;
  3100.                     nBarWidth                                                     ,;
  3101.                     aValues[nI+1,nJ+2] / ABS( nMinValue - nMaxValue)*nGraphHeight ,;
  3102.                     nJ+2                                                          ,;
  3103.                     nStyle                                                         ;
  3104.                   )
  3105.       NEXT nJ
  3106.  
  3107.                              // Write legends on X axis only for first pass
  3108.       gWriteAt(nYPosition + nI * nIncrement                          ,;
  3109.                nGraphBottom + (nI % nXLegNbLine ) * FONT_SIZE_Y + 2  ,;
  3110.                aValues[nI+1,1]                                       ,;
  3111.                nXAxisColor                                           ,;
  3112.                LLG_MODE_SET                                           ;
  3113.               )
  3114.  
  3115.       gLine( nYPosition + nI * nIncrement   ,;
  3116.              nXPosition                     ,;
  3117.              nYPosition + nI * nIncrement   ,;
  3118.              nXPosition + 3                 ,;
  3119.              nXAxisColor                    ,;
  3120.              LLG_MODE_SET                    ;
  3121.            )
  3122.  
  3123.    NEXT nI
  3124.  
  3125.                              // Reset previous clipping area
  3126.    gSetClip( aOldClip[1] ,;
  3127.              aOldClip[2] ,;
  3128.              aOldClip[3] ,;
  3129.              aOldClip[4]  ;
  3130.            )
  3131.  
  3132.    RETURN (NIL)
  3133.  
  3134.  
  3135. *
  3136. FUNCTION DrawValue( nLeft    ,; // Left coordinates in pixels
  3137.                     nTop     ,; // Top coordinates in pixels
  3138.                     nWidth   ,; // Width in pixels
  3139.                     nHeight  ,; // Height in pixels
  3140.                     nColor   ,; // Color
  3141.                     nStyle    ; // Style
  3142.                   )
  3143.  
  3144.    STATIC aPrevCoord := {}   // Coordinates of previous drawn values
  3145.  
  3146.  
  3147.    LOCAL nI       := 0       // Loop pointer
  3148.    LOCAL nPointer := 0       // ASCAN pointer
  3149.    LOCAL nDepth   := 0       // Depth of 3D graphs
  3150.  
  3151.    IF nStyle == NIL          // No parameters => reset aPrevCoord
  3152.       nStyle := 99
  3153.    ELSEIF nStyle == STYLE_BAR_3D .OR. nStyle == STYLE_LINE_3D
  3154.                              // 3D graph, define depth
  3155.       nDepth := MIN(nWidth/4,10)
  3156.    ELSE
  3157.                              // depth = 0
  3158.       nDepth := 0
  3159.    ENDIF
  3160.  
  3161.                              // Style BARGRAPH
  3162.    IF nStyle == STYLE_BAR .OR. nStyle == STYLE_BAR_3D
  3163.  
  3164.                              // Depth no null 3D bars
  3165.       IF nDepth > 0
  3166.                              // Fill background whith gray for 3D bar
  3167.          FOR nI := 1 TO nDepth
  3168.  
  3169.             gRect( nLeft + nI              ,;
  3170.                    nTop - nI               ,;
  3171.                    nLeft + nWidth + nI     ,;
  3172.                    nTop - nHeight - nI     ,;
  3173.                    LLG_FRAME               ,;
  3174.                    8                       ,;
  3175.                    LLG_MODE_SET             ;
  3176.                  )
  3177.  
  3178.          NEXT nI
  3179.                              // Draw 3D bar depth lines
  3180.       gLine( nLeft                   ,;
  3181.              nTop                    ,;
  3182.              nLeft + nDepth          ,;
  3183.              nTop - nDepth           ,;
  3184.              4                       ,;
  3185.              LLG_MODE_SET             ;
  3186.            )
  3187.  
  3188.       gLine( nLeft                   ,;
  3189.              nTop - nHeight          ,;
  3190.              nLeft + nDepth          ,;
  3191.              nTop - nHeight - nDepth ,;
  3192.              4                       ,;
  3193.              LLG_MODE_SET             ;
  3194.            )
  3195.  
  3196.       gLine( nLeft + nWidth          ,;
  3197.              nTop                    ,;
  3198.              nLeft + nWidth + nDepth ,;
  3199.              nTop - nDepth           ,;
  3200.              4                       ,;
  3201.              LLG_MODE_SET             ;
  3202.            )
  3203.  
  3204.       gLine( nLeft + nWidth          ,;
  3205.              nTop - nHeight          ,;
  3206.              nLeft + nWidth + nDepth ,;
  3207.              nTop - nHeight - nDepth ,;
  3208.              4                       ,;
  3209.              LLG_MODE_SET             ;
  3210.            )
  3211.  
  3212.  
  3213.                              // Draw frame arround background
  3214.       gRect( nLeft + nDepth           ,;
  3215.              nTop - nDepth            ,;
  3216.              nLeft + nWidth + nDepth  ,;
  3217.              nTop - nHeight - nDepth  ,;
  3218.              LLG_FRAME                ,;
  3219.              4                        ,;
  3220.              LLG_MODE_SET              ;
  3221.            )
  3222.  
  3223.    ENDIF
  3224.                              // Draw front colored bar
  3225.    gRect( nLeft                       ,;
  3226.           nTop                        ,;
  3227.           nLeft + nWidth              ,;
  3228.           nTop - nHeight              ,;
  3229.           LLG_FILL                    ,;
  3230.           nColor                      ,;
  3231.           LLG_MODE_SET                 ;
  3232.         )
  3233.  
  3234.                              // Draw frame arround colored bar
  3235.    gRect( nLeft                       ,;
  3236.           nTop                        ,;
  3237.           nLeft + nWidth              ,;
  3238.           nTop - nHeight              ,;
  3239.           LLG_FRAME                   ,;
  3240.           4                           ,;
  3241.           LLG_MODE_SET                 ;
  3242.         )
  3243.  
  3244.                              // Style LINEGRAPH
  3245.    ELSEIF nStyle == STYLE_LINE .OR. nStyle == STYLE_LINE_3D
  3246.  
  3247.       IF nDepth == 0
  3248.                              // Draw cross arround point location
  3249.                              // with two lines
  3250.          gLine( nLeft - 2                ,;
  3251.                 nTop - nHeight-2         ,;
  3252.                 nLeft + 2                ,;
  3253.                 nTop  - nHeight + 2      ,;
  3254.                 nColor                   ,;
  3255.                 LLG_MODE_SET              ;
  3256.               )
  3257.  
  3258.           gLine( nLeft + 2                ,;
  3259.                  nTop - nHeight - 2       ,;
  3260.                  nLeft - 2                ,;
  3261.                  nTop - nHeight + 2       ,;
  3262.                  nColor                   ,;
  3263.                  LLG_MODE_SET              ;
  3264.                )
  3265.  
  3266.       ENDIF
  3267.  
  3268.  
  3269.  
  3270.                              // Locate coordinates of previous point
  3271.                              // with same color
  3272.       nPointer  := ASCAN(aPrevCoord, { |aElem| aElem[1] == nColor  })
  3273.  
  3274.                              // Previous point found
  3275.       IF nPointer  <> 0
  3276.          FOR nI := 0 TO nDepth
  3277.                              // Draw line between previous point
  3278.                              // and current point
  3279.              gLine( aPrevCoord[nPointer ,2]+nI  ,;
  3280.                     aPrevCoord[nPointer ,3]-nI  ,;
  3281.                     nLeft + nI                  ,;
  3282.                     nTop - nHeight - nI         ,;
  3283.                     nColor                      ,;
  3284.                     LLG_MODE_SET                 ;
  3285.                   )
  3286.  
  3287.          NEXT nI
  3288.  
  3289.       ELSE                   // Previous point not found
  3290.                              // (first point)
  3291.                              // Add an element to coordinates array
  3292.                              // for current color
  3293.          AADD(aPrevCoord,{nColor,NIL,NIL})
  3294.          nPointer  := LEN(aPrevCoord)
  3295.  
  3296.       ENDIF
  3297.                              // Store current point coordinates for next point
  3298.       aPrevCoord[nPointer ,2] := nLeft
  3299.       aPrevCoord[nPointer ,3] := nTop - nHeight
  3300.  
  3301.    ELSE                      // Style not bar, not line
  3302.                              // reset coordinates array
  3303.       aPrevCoord := {}
  3304.  
  3305.    ENDIF
  3306.  
  3307.    RETURN (NIL)
  3308.  
  3309. *
  3310. FUNCTION CirGraph( nTop     ,;  // Top coordinates in rows
  3311.                    nleft    ,;  // Left coordinates in columns
  3312.                    nBottom  ,;  // Bottom coordinates in rows
  3313.                    nRight   ,;  // Right coordinates in columns
  3314.                    aValues   ;  // Array of values
  3315.                  )
  3316.  
  3317.    LOCAL aOldClip     := {}                               // Previous Clipping region
  3318.  
  3319.    LOCAL nI           := 0                                // Loop pointer
  3320.    LOCAL nJ           := 0                                // Loop pointer
  3321.  
  3322.    LOCAL nGraphTop    := (nTop * FONT_SIZE_Y + 20)        // Top   limit of graph area
  3323.    LOCAL nGraphleft   := (nLeft * FONT_SIZE_X + 16 +10 )  // Left     ""
  3324.    LOCAL nGraphBottom := (nBottom * FONT_SIZE_Y - 20)     // Bottom   ""
  3325.    LOCAL nGraphRight  := (nRight * FONT_SIZE_X - 16 -10)  // Right    ""
  3326.  
  3327.                                                           // Center of Ellipse
  3328.    LOCAL nXCenter     := nGraphLeft + ( nGraphRight - nGraphLeft )/2
  3329.    LOCAL nYCenter     := nGraphTop  + ( nGraphBottom - nGraphTop )/2
  3330.  
  3331.    LOCAL nXSize       := ( nGraphRight - nGraphLeft )/2
  3332.    LOCAL nYSize       := nXSize / 3
  3333.  
  3334.    LOCAL nTotal       := 0                                // Sum of all values == 100%
  3335.    LOCAL nAngleBeg    := 0                                // Begining of sector
  3336.    LOCAL nAngleEnd    := 0                                // End of sector
  3337.  
  3338.                              // Define clipping region to avoid
  3339.                              // writing outside graph
  3340.    aOldClip := gSetClip( nLeft   * FONT_SIZE_X  ,;
  3341.                          nTop    * FONT_SIZE_Y  ,;
  3342.                          nRight  * FONT_SIZE_X  ,;
  3343.                          nBottom * FONT_SIZE_Y   ;
  3344.                        )
  3345.  
  3346.                              // Draw box arround graph
  3347.    gFrame( nLeft   * FONT_SIZE_X     ,;
  3348.            nTop    * FONT_SIZE_Y     ,;
  3349.            nRight  * FONT_SIZE_X - 1 ,;
  3350.            nBottom * FONT_SIZE_Y - 1 ,;
  3351.            7, 15, 8                  ,;
  3352.            5, 5, 5, 5                ,;
  3353.            LLG_MODE_SET               ;
  3354.          )
  3355.  
  3356.                              // Compute sum of values to display
  3357.    FOR nI := 1 TO LEN(aValues)
  3358.        nTotal += aValues[nI,2]
  3359.    NEXT
  3360.  
  3361.                              // Draw values
  3362.    FOR nI := 1 TO LEN(aValues)
  3363.                              // Compute percentage
  3364.       nAngleEnd := nAngleBeg + INT(360 * aValues[nI,2]/nTotal)
  3365.  
  3366.       IF nI==LEN(aValues)    // Force last value to 360
  3367.          nAngleEnd := 360
  3368.       ENDIF
  3369.                              // Draw part of ellipse
  3370.       gEllipse( nXCenter      ,;
  3371.                 nYCenter      ,;
  3372.                 nXSize        ,;
  3373.                 nYSize        ,;
  3374.                 nAngleBeg     ,;
  3375.                 nAngleEnd     ,;
  3376.                 LLG_FILL      ,;
  3377.                 IF(nI==7,2,nI),;
  3378.                 LLG_MODE_SET   ;
  3379.               )
  3380.  
  3381.                              // Next sector begining is current sector end
  3382.       nAngleBeg := nAngleEnd
  3383.  
  3384.    NEXT nI
  3385.  
  3386.                              // Reset Clipping region
  3387.    gSetClip( aOldClip[1] ,;
  3388.              aOldClip[2] ,;
  3389.              aOldClip[3] ,;
  3390.              aOldClip[4]  ;
  3391.            )
  3392.  
  3393.    RETURN (NIL)
  3394.  
  3395.  
  3396. *
  3397. STATIC FUNCTION nRoundSup( nValue )
  3398.  
  3399.  
  3400.    LOCAL nReturn  := 0       // Return value
  3401.  
  3402.                              // Sign of value
  3403.    LOCAL nSign    := INT( nValue/ABS(nValue) )
  3404.  
  3405.                              // Length of value
  3406.    LOCAL nValLen  := LEN( ALLTRIM( STR( INT( nSign * nValue ) ) ) )
  3407.  
  3408.    LOCAL nTmpVal  := 0       // Temp Value
  3409.    LOCAL nNearest := 0       // Nearest rounded value of nValue
  3410.  
  3411.  
  3412.                              // First rounds value
  3413.                              // 855 => 900
  3414.                              // 820 => 800
  3415.    nNearest := ROUND( nSign * nValue, -nValLen + 1)
  3416.  
  3417.                              // Keep nearest value
  3418.    nReturn  := nNearest
  3419.  
  3420.    nTmpVal := nValue
  3421.  
  3422.    DO WHILE nSign * nValue > nReturn
  3423.                              // If value > rounded value,
  3424.                              // then try rounding a greater value
  3425.                              // Loop #1    820 * 820 / 800 = 840.5 => 800
  3426.                              // Loop #2    840 * 840 / 800 = 882   => 900
  3427.       nTmpVal := nTmpVal*nTmpVal / nNearest
  3428.       nReturn := ROUND(nTmpVal,-nValLen+1 )
  3429.    ENDDO
  3430.  
  3431.    RETURN (nSign * nReturn)
  3432.  
  3433.  
  3434.  
  3435.  
  3436.  
  3437.  
  3438.  
  3439.  
  3440. *
  3441.                              // Group Menu To
  3442.                              // Note : Here are some CA-CLIPPER
  3443.                              // modified functions to allow mouse
  3444.                              // and graphics use of Menu To
  3445.                              // Do not change them until you want to change
  3446.                              // the behaviour of MENU TO
  3447. /***
  3448. *
  3449. *  @ ...,... PROMPT ... MESSAGE ...  / MENU TO
  3450. *
  3451. *  Standard MENU TO replacement system
  3452. *
  3453. */
  3454. *
  3455. #DEFINE n_Prompt_Row     1
  3456. #DEFINE n_Prompt_Col     2
  3457. #DEFINE n_Prompt_Col_End 3
  3458. #DEFINE c_Prompt_Item    4
  3459. #DEFINE c_Prompt_Msg     5
  3460. #DEFINE c_Prompt_Key     6
  3461.  
  3462.  
  3463. *
  3464. FUNCTION __AtPrompt(nRow,nCol,cPrompt,cMsg)
  3465.  
  3466.  
  3467.    AADD(aPrompt , { nRow                        ,;
  3468.                     nCol                        ,;
  3469.                     nCol+LEN(cPrompt)-1         ,;
  3470.                     cPrompt                     ,;
  3471.                     cMsg                        ,;
  3472.                     UPPER(LEFT(cPrompt+" ",1))   ;
  3473.                   }                              ;
  3474.        )
  3475.  
  3476.    DEVPOS(nRow,nCol)
  3477.    DEVOUT(cPrompt)
  3478.  
  3479.    RETURN (NIL)
  3480.  
  3481.  
  3482.  
  3483. *
  3484. FUNCTION __MenuTo(bChoice,cVarName)
  3485.  
  3486.    LOCAL nChoice        := 1
  3487.    LOCAL nChoOld        := 1
  3488.  
  3489.    LOCAL nI             := 0
  3490.    LOCAL nKey           := 0
  3491.  
  3492.    LOCAL aState         := LLM_INIT_STATE
  3493.  
  3494.    LOCAL lExitRequested := .F.
  3495.    LOCAL lNeedRefresh   := .F.
  3496.    LOCAL lNoEvent       := .T.
  3497.  
  3498.    LOCAL nSaveRow       := ROW()
  3499.    LOCAL nSaveCol       := COL()
  3500.    LOCAL nSaveCur       := SETCURSOR()
  3501.    LOCAL cSaveColor     := SETCOLOR()
  3502.  
  3503.    LOCAL cColorHig      := ""
  3504.    LOCAL lWrapMode      := Set( _SET_WRAP )
  3505.  
  3506.    LOCAL aLocalPrompt   := {}
  3507.  
  3508.    nChoice := EVAL(bChoice,1)
  3509.  
  3510.    IF LEN(aPrompt)==0
  3511.       RETURN (0)
  3512.    ENDIF
  3513.  
  3514.    nChoice := IF(nChoice>0 .AND. nChoice<=LEN(aPrompt),nChoice,1)
  3515.  
  3516.    cColorHig := RIGHT(cSaveColor,LEN(cSaveColor)-AT(",",cSaveColor+","))
  3517.    cColorHig := LEFT(cColorHig,AT(",",cColorHig)-1)
  3518.  
  3519.  
  3520.    SETCURSOR(0)
  3521.  
  3522.    __MenuToMsg(aPrompt[nChoice,c_Prompt_Msg])
  3523.    SETCOLOR(cColorHig)
  3524.    DEVPOS(aPrompt[nChoice,n_Prompt_Row],aPrompt[nChoice,n_Prompt_Col])
  3525.    DEVOUT(aPrompt[nChoice,c_Prompt_Item])
  3526.    SETCOLOR(cSaveColor)
  3527.  
  3528.    mShow()
  3529.    aState := LLM_INIT_STATE
  3530.    lExitRequested := .F.
  3531.  
  3532.    DO WHILE !lExitRequested
  3533.  
  3534.       lNoEvent := .T.
  3535.       DO WHILE lNoEvent
  3536.  
  3537.          IF (nKey:=INKEY())<>0
  3538.  
  3539.             IF ( SETKEY(nKey)<>NIL )
  3540.  
  3541.                aLocalPrompt := ACLONE(aPrompt)
  3542.                aPrompt := {}
  3543.                EVAL( SETKEY(nKey) ,PROCNAME(1),PROCLINE(1),cVarName )
  3544.                aPrompt := ACLONE(aLocalPrompt)
  3545.                LOOP
  3546.  
  3547.             ENDIF
  3548.  
  3549.             lNoEvent := .F.
  3550.  
  3551.          ELSE
  3552.  
  3553.             aState:=mState()
  3554.             IF aState[LLM_STATE_LEFT]==LLM_BUTTON_DOWN .OR. aState[LLM_STATE_RIGHT]==LLM_BUTTON_DOWN
  3555.                lNoEvent := .F.
  3556.             ENDIF
  3557.  
  3558.          ENDIF
  3559.       ENDDO
  3560.  
  3561.       lNeedRefresh  := .F.
  3562.  
  3563.       DO CASE
  3564.  
  3565.          CASE nKey==K_ESC .OR. nKey==K_ENTER
  3566.               lExitRequested := .T.
  3567.  
  3568.          CASE nKey==K_LEFT .OR. nKey==K_UP
  3569.  
  3570.               lNeedRefresh := .T.
  3571.               nChoice -= 1
  3572.               IF nChoice==0
  3573.                  IF lWrapMode
  3574.                     nChoice := LEN(aPrompt)
  3575.                  ELSE
  3576.                     nChoice := 1
  3577.                  ENDIF
  3578.               ENDIF
  3579.  
  3580.          CASE nKey==K_RIGHT .OR. nKey==K_DOWN
  3581.  
  3582.               lNeedRefresh := .T.
  3583.               nChoice += 1
  3584.               IF nChoice==LEN(aPrompt)+1
  3585.                  IF lWrapMode
  3586.                     nChoice := 1
  3587.                  ELSE
  3588.                     nChoice := LEN(aPrompt)
  3589.                  ENDIF
  3590.               ENDIF
  3591.  
  3592.  
  3593.          CASE aState[LLM_STATE_RIGHT]==LLM_BUTTON_DOWN
  3594.  
  3595.               lExitRequested := .T.
  3596.  
  3597.  
  3598.          CASE aState[LLM_STATE_LEFT]==LLM_BUTTON_DOWN
  3599.  
  3600.               lExitRequested := .F.
  3601.               FOR nI := 1 TO LEN(aPrompt)
  3602.                   IF aState[LLM_STATE_ROW]==aPrompt[nI,n_Prompt_Row] .AND. ;
  3603.                      aState[LLM_STATE_COL]>=aPrompt[nI,n_Prompt_Col] .AND. ;
  3604.                      aState[LLM_STATE_COL]<=aPrompt[nI,n_Prompt_Col_End]
  3605.  
  3606.                      nChoice := nI
  3607.                      lNeedRefresh := .T.
  3608.                      lExitRequested := .T.
  3609.                      EXIT
  3610.  
  3611.                   ENDIF
  3612.               NEXT
  3613.  
  3614.               IF !lExitRequested
  3615.                  nChoice := nChoOld
  3616.               ENDIF
  3617.  
  3618.          OTHERWISE
  3619.  
  3620.               IF nKey<>0
  3621.  
  3622.                  nChoice := ASCAN(aPrompt,{|el| el[c_Prompt_Key]==UPPER(CHR(nKey)) })
  3623.  
  3624.                  IF nChoice <> 0
  3625.  
  3626.                     lNeedRefresh := .T.
  3627.                     lExitRequested := .T.
  3628.  
  3629.                  ELSE
  3630.  
  3631.                     nChoice := nChoOld
  3632.  
  3633.                  ENDIF
  3634.  
  3635.  
  3636.               ENDIF
  3637.  
  3638.       ENDCASE
  3639.  
  3640.       mHide()
  3641.  
  3642.       IF lNeedRefresh
  3643.  
  3644.          DEVPOS(aPrompt[nChoOld,n_Prompt_Row],aPrompt[nChoOld,n_Prompt_Col])
  3645.          DEVOUT(aPrompt[nChoOld,c_Prompt_Item])
  3646.  
  3647.          __MenuToMsg(aPrompt[nChoice,c_Prompt_Msg])
  3648.          SETCOLOR(cColorHig)
  3649.          DEVPOS(aPrompt[nChoice,n_Prompt_Row],aPrompt[nChoice,n_Prompt_Col])
  3650.          DEVOUT(aPrompt[nChoice,c_Prompt_Item])
  3651.          SETCOLOR(cSaveColor)
  3652.  
  3653.          nChoOld := nChoice
  3654.  
  3655.       ENDIF
  3656.  
  3657.       mShow()
  3658.  
  3659.    ENDDO
  3660.  
  3661.    IF nKey==K_ESC .OR. aState[LLM_STATE_RIGHT]==LLM_BUTTON_DOWN
  3662.       nChoice := 0
  3663.    ENDIF
  3664.  
  3665.    mHide()
  3666.    DEVPOS(nSaveRow,nSaveCol)
  3667.    SETCURSOR(nSaveCur)
  3668.    SETCOLOR(cSaveColor)
  3669.  
  3670.    aPrompt := {}
  3671.  
  3672.    RETURN (nChoice)
  3673.  
  3674. *
  3675. FUNCTION __MenuToMsg(cMsg)
  3676.  
  3677.    STATIC cOldMsg := ""
  3678.    STATIC nOldRow := 0
  3679.    STATIC nOldCol := 0
  3680.  
  3681.  
  3682.    DEVPOS(nOldRow,nOldCol)
  3683.    DEVOUT(SPACE(LEN(cOldMsg)))
  3684.  
  3685.    cOldMsg := cMsg
  3686.  
  3687.    nOldRow := Set( _SET_MESSAGE )
  3688.  
  3689.    IF Set( _SET_MCENTER )
  3690.  
  3691.       nOldCol := INT( (MAXCOL()-LEN(cMsg))/2 )
  3692.  
  3693.    ELSE
  3694.  
  3695.       nOldCol := 0
  3696.  
  3697.    ENDIF
  3698.  
  3699.    DEVPOS(nOldRow,nOldCol)
  3700.    DEVOUT(cOldMsg)
  3701.  
  3702.    RETURN (NIL)
  3703.  
  3704. *
  3705.                              // Group Extended Gets - CHECK GETS
  3706.                              // Note : Here are some very simples
  3707.                              // CA-CLIPPER generics functions to extend
  3708.                              // GET/READ capability
  3709. /***
  3710. *
  3711. *  ChkAddGet()          Add a checkbox Get
  3712. *  ChkGetReader()       Special reader for checkbox Get
  3713. *  ChkGetApplyKey()     Checkbox Get apply key
  3714. *  ChkButDisp()         Display the checkbox button
  3715. *  ChkOnOff()           Switch chkbox button state
  3716. *
  3717. */
  3718. *
  3719. FUNCTION ChkAddGet(bSetGetVar     ,;  // Set Get block on master variable
  3720.                    cVarName       ,;  // Variable name
  3721.                    aGetList       ,;  // Related gets
  3722.                    aCtrlButtons   ,;  // Related buttons
  3723.                    cSayExp         ;  // Expression
  3724.                   )
  3725.                              // Add a check box Get
  3726.  
  3727.    LOCAL oGet                // Temporary get object
  3728.  
  3729.                              // Cursor location
  3730.    LOCAL nRow         := ROW()
  3731.    LOCAL nCol         := COL()
  3732.  
  3733.    LOCAL cI           := ''  // Temporary
  3734.  
  3735.                              // Create a new empty GET object
  3736.    oGet := GETNEW(nRow,nCol+2,bSetGetVar,cVarName)
  3737.  
  3738.                              // Add it to the Get List
  3739.    AADD(aGetList,oGet)
  3740.  
  3741.  
  3742.                              // Set the reader to the ChkReader
  3743.    oGet:reader := { |oG,GetList,aButtons| ChkGetReader(oG,GetList,aButtons) }
  3744.  
  3745.                              // Use cargo to store Say Expression
  3746.    oGet:cargo := { cSayExp, '' , '' }
  3747.                              // Use some translate to make it clearer
  3748.    #XTRANSLATE :cSayExp   => :cargo\[1\]
  3749.    #XTRANSLATE :cUnselCol => :cargo\[2\]
  3750.    #XTRANSLATE :cSelecCol => :cargo\[3\]
  3751.  
  3752.                              // Extract selected color from colorstring
  3753.    cI := SETCOLOR()
  3754.    cI := RIGHT(cI,LEN(cI)-AT(',',cI))
  3755.    oGet:cSelecCol := LEFT(cI,AT(',',cI)-1)
  3756.  
  3757.                              // Extract unselected color from colorstring
  3758.    cI := SETCOLOR()
  3759.    oGet:cUnselCol := RIGHT(cI,LEN(cI)-RAT(',',cI))
  3760.  
  3761.    DEVPOS(oGet:row,oGet:col)
  3762.    DEVOUT(oGet:cSayExp,oGet:cUnselCol)
  3763.  
  3764.                              // Add a button to manage radio
  3765.    @ FONT_SIZE_X * (oGet:col - 2 )                          ,;
  3766.      FONT_SIZE_Y * oGet:row                                 ,;
  3767.      FONT_SIZE_X * oGet:col - 1                             ,;
  3768.      FONT_SIZE_Y * ( oGet:row + 1 ) - 1                      ;
  3769.      BUTTON                                                  ;
  3770.      STYLE BUTTON_TYPE_RELEASE                               ;
  3771.      ACTION { |x,y,aButton| ChkOnOff(x,y,aButton,aGetList) } ;
  3772.      DISPLAYUP { |nL,nT,nR,nB,xCargo| ChkButDisp(oGet,.T.) } ;
  3773.      DISPLAYDN { |nL,nT,nR,nB,xCargo| ChkButDisp(oGet,.F.) } ;
  3774.      CARGO LEN(aGetList)                                     ;
  3775.      ATTACH aCtrlButtons
  3776.  
  3777.    RETURN (oGet)
  3778.  
  3779. *
  3780. FUNCTION ChkGetReader(oGet         ,;  // Object to be read
  3781.                       aGetList     ,;  // Related gets objects
  3782.                       aCtrlButtons  ;  // Related buttons
  3783.                      )
  3784.                              // Special reader for checkbox Get
  3785.  
  3786.                              // Needs some variables to manage Mouse and buttons
  3787.    LOCAL nKey
  3788.    LOCAL nCurrentGet
  3789.  
  3790.  
  3791.                              // Record reference of current get in GetList
  3792.    nCurrentGet := Ascan(aGetList, {|o| o==oGet })
  3793.  
  3794.                              // If needed, reach the requested get
  3795.    IF !(nHitGet()==NIL) .AND. nCurrentGet<>nHitGet()
  3796.  
  3797.       IF nCurrentGet > nHitGet()
  3798.          oGet:exitstate := GE_UP
  3799.       ELSE
  3800.          oGet:exitstate := GE_DOWN
  3801.       ENDIF
  3802.  
  3803.    ELSE
  3804.  
  3805.                              // Reset GetGoTo Set/Get function
  3806.       nHitGet(NIL)
  3807.  
  3808.                              // Read the GET if the WHEN condition is satisfied
  3809.       IF ( GetPreValidate( oGet ) )
  3810.  
  3811.                              // Do not give focus to this get, in this case
  3812.                              // it will display the value
  3813.  
  3814.                              // Display the SayExpr instead of the get value
  3815.          DEVPOS(oGet:row,oGet:col)
  3816.          DEVOUT(oGet:cSayExp,oGet:cSelecCol)
  3817.                              // Reset cursor position
  3818.          DEVPOS(oGet:row,oGet:col)
  3819.  
  3820.  
  3821.          WHILE ( oGet:exitState == GE_NOEXIT )
  3822.  
  3823.                              // Apply keystrokes until exit
  3824.             WHILE ( oGet:exitState == GE_NOEXIT )
  3825.  
  3826.                nKey := mInkey( 0 ,aCtrlButtons ,aGetList )
  3827.  
  3828.                IF nKey == K_BUTTON .OR. nKey == K_ACCELERATOR
  3829.  
  3830.                              // Nothing To do
  3831.  
  3832.                ELSEIF nKey == K_GET
  3833.  
  3834.                   IF nCurrentGet > nHitGet()
  3835.                              // Get field clicked is up
  3836.                      oGet:exitState := GE_UP
  3837.                   ELSEIF nCurrentGet < nHitGet()
  3838.                              // Get field clicked is down
  3839.                      oGet:exitState := GE_DOWN
  3840.                   ENDIF
  3841.  
  3842.                ELSE
  3843.                              // Apply the key to the get object
  3844.                   ChkGetApplyKey( oGet, nKey )
  3845.  
  3846.                ENDIF
  3847.  
  3848.             ENDDO
  3849.  
  3850.                              // Disallow exit if the VALID condition
  3851.                              // is not satisfied
  3852.             IF ( !GetPostValidate( oGet ) )
  3853.                oGet:exitState := GE_NOEXIT
  3854.             ENDIF
  3855.  
  3856.          ENDDO
  3857.  
  3858.                              // Display the SayExpr instead of the get value
  3859.          DEVPOS(oGet:row,oGet:col)
  3860.          DEVOUT(oGet:cSayExp,oGet:cUnselCol)
  3861.                              // Reset cursor position
  3862.          DEVPOS(oGet:row,oGet:col)
  3863.  
  3864.       ENDIF
  3865.  
  3866.    ENDIF
  3867.  
  3868.    RETURN (NIL)
  3869.  
  3870.  
  3871. *
  3872. FUNCTION ChkGetApplyKey(oGet     ,;  // Get object
  3873.                         nKey     ,;  // Key number
  3874.                         aGetList  ;  // List of related gets
  3875.                        )
  3876.  
  3877.                              // Checkbox Get apply key
  3878.  
  3879.    LOCAL bKeyBlock
  3880.  
  3881.                              // Check for SET KEY first
  3882.    IF ( (bKeyBlock := SetKey(nKey)) <> NIL )
  3883.  
  3884.       GetDoSetKey(bKeyBlock, oGet)
  3885.       RETURN(NIL)
  3886.  
  3887.    ENDIF
  3888.  
  3889.  
  3890.    DO CASE
  3891.  
  3892.       CASE ( nKey == K_UP )
  3893.            oGet:exitState := GE_UP
  3894.  
  3895.       CASE ( nKey == K_SH_TAB )
  3896.            oGet:exitState := GE_UP
  3897.  
  3898.       CASE ( nKey == K_DOWN )
  3899.            oGet:exitState := GE_DOWN
  3900.  
  3901.       CASE ( nKey == K_TAB )
  3902.            oGet:exitState := GE_DOWN
  3903.  
  3904.       CASE ( nKey == K_ENTER )
  3905.            oGet:exitState := GE_ENTER
  3906.  
  3907.       CASE ( nKey == 32 )    // use space bar to toggle the chkbox button
  3908.  
  3909.                              // change .T. in .F. or .F. in .T.
  3910.            oGet:varput(!oGet:varget())
  3911.  
  3912.                              // redisplay check box button
  3913.            ChkButDisplay( oGet , .T. )
  3914.  
  3915.       CASE ( nKey == K_ESC )
  3916.            IF ( SET(_SET_ESCAPE) )
  3917.               oGet:undo()
  3918.               oGet:exitState := GE_ESCAPE
  3919.            ENDIF
  3920.  
  3921.       CASE ( nKey == K_PGUP )
  3922.            oGet:exitState := GE_WRITE
  3923.  
  3924.       CASE ( nKey == K_PGDN )
  3925.            oGet:exitState := GE_WRITE
  3926.  
  3927.       CASE ( nKey == K_CTRL_HOME )
  3928.            oGet:exitState := GE_TOP
  3929.  
  3930.       CASE (nKey == K_CTRL_W)
  3931.            oGet:exitState := GE_WRITE
  3932.  
  3933.       CASE (nKey == K_INS)
  3934.            SET( _SET_INSERT, !SET(_SET_INSERT) )
  3935.            ShowScoreboard()
  3936.  
  3937.    ENDCASE
  3938.  
  3939. RETURN (NIL)
  3940.  
  3941.  
  3942. *
  3943. FUNCTION ChkButDisp(oGet       ,; // Get object
  3944.                     lDisplayUp  ; // Display in up or down position
  3945.                    )
  3946.  
  3947.                              // Display the checkbox button
  3948.  
  3949.    IF oGet:varget()
  3950.                              // If the get is selected
  3951.  
  3952.       gBmpDisp(IF(lDisplayUp,aBmpBase[CHECK_F_UP],aBmpBase[CHECK_F_DW]),;
  3953.                FONT_SIZE_X * (oGet:col - 2 )                           ,;
  3954.                FONT_SIZE_Y * oGet:row                                   ;
  3955.               )
  3956.  
  3957.    ELSE                      // If the get is not selected
  3958.  
  3959.       gBmpDisp(IF(lDisplayUp,aBmpBase[CHECK_E_UP],aBmpBase[CHECK_E_DW]),;
  3960.                FONT_SIZE_X * (oGet:col - 2 )                           ,;
  3961.                FONT_SIZE_Y * oGet:row                                   ;
  3962.               )
  3963.  
  3964.    ENDIF
  3965.  
  3966.  
  3967.    RETURN (NIL)
  3968.  
  3969.  
  3970.  
  3971.  
  3972. *
  3973. FUNCTION ChkOnOff(nMouseX   ,;  // Mouse pixels locations
  3974.                   nMouseY   ,;  //
  3975.                   aButton   ,;  // Pointer on the button
  3976.                   aGetList   ;  // List of related get
  3977.                  )
  3978.  
  3979.                              // Switch chkbox button state
  3980.  
  3981.  
  3982.                              // Retrieve the get object using button cargo
  3983.                              // which contains the number of the get in the
  3984.                              // list
  3985.    LOCAL oGet := aGetList[aButton[BUTTON_CARGO]]
  3986.  
  3987.    oGet:varput(!oGet:varget())
  3988.  
  3989.    ChkButDisplay( oGet , .T. )
  3990.  
  3991.  
  3992.    RETURN (NIL)
  3993.  
  3994.  
  3995.  
  3996. *
  3997.                              // Group Extended Gets - INCREMENTAL GETS
  3998.                              // Note : Here are some very simples
  3999.                              // CA-CLIPPER generics functions to extend
  4000.                              // GET/READ capability
  4001. /***
  4002. *
  4003. *  IncreGetReader()     Special reader for incremental Get
  4004. *  IncrGetApplyKey()    Incremental Get apply key for + and - keys
  4005. *  IncreButton()        Define a button to allow incremental action on a get
  4006. *  IncreVal()           Action to be executed when incremental button is down
  4007. *
  4008. */
  4009.  
  4010. *
  4011. FUNCTION IncrGetReader(oGet         ,;  // Object to be read
  4012.                        aGetList     ,;  // Related gets objects
  4013.                        aCtrlButtons  ;  // Related buttons
  4014.                       )
  4015.                              // Special reader for incremental Get
  4016.  
  4017.                              // Needs some variables to manage Mouse and buttons
  4018.    LOCAL nKey
  4019.    LOCAL nCurrentGet
  4020.  
  4021.  
  4022.                              // Record reference of current get in GetList
  4023.    nCurrentGet := Ascan(aGetList, {|o| o==oGet })
  4024.  
  4025.                              // If needed, reach the requested get
  4026.    IF !(nHitGet()==NIL) .AND. nCurrentGet<>nHitGet()
  4027.  
  4028.       IF nCurrentGet > nHitGet()
  4029.          oGet:exitstate := GE_UP
  4030.       ELSE
  4031.          oGet:exitstate := GE_DOWN
  4032.       ENDIF
  4033.  
  4034.    ELSE
  4035.  
  4036.                              // Reset GetGoTo Set/Get function
  4037.       nHitGet(NIL)
  4038.  
  4039.                              // Read the GET if the WHEN condition is satisfied
  4040.       IF ( GetPreValidate( oGet ) )
  4041.  
  4042.                              // Activate the GET for reading
  4043.          oGet:setFocus()
  4044.  
  4045.          WHILE ( oGet:exitState == GE_NOEXIT )
  4046.  
  4047.                              // Check for initial typeout (no editable positions)
  4048.             IF ( oGet:typeOut )
  4049.                oGet:exitState := GE_ENTER
  4050.             ENDIF
  4051.  
  4052.  
  4053.                              // Apply keystrokes until exit
  4054.             WHILE ( oGet:exitState == GE_NOEXIT )
  4055.  
  4056.                nKey := mInkey( 0 ,aCtrlButtons ,aGetList )
  4057.  
  4058.                IF nKey == K_BUTTON .OR. nKey == K_ACCELERATOR
  4059.  
  4060.                              // Nothing To do
  4061.  
  4062.                ELSEIF nKey == K_GET
  4063.  
  4064.                   IF nCurrentGet > nHitGet()
  4065.                              // Get field clicked is up
  4066.                      oGet:exitState := GE_UP
  4067.                   ELSEIF nCurrentGet < nHitGet()
  4068.                              // Get field clicked is down
  4069.                      oGet:exitState := GE_DOWN
  4070.                   ENDIF
  4071.  
  4072.                ELSE
  4073.                              // Apply the key to the get object
  4074.                   IncrGetApplyKey( oGet, nKey )
  4075.  
  4076.                ENDIF
  4077.  
  4078.             ENDDO
  4079.  
  4080.                              // Disallow exit if the VALID condition
  4081.                              // is not satisfied
  4082.             IF ( !GetPostValidate( oGet ) )
  4083.                oGet:exitState := GE_NOEXIT
  4084.             ENDIF
  4085.  
  4086.          ENDDO
  4087.  
  4088.          oGet:killFocus()    // De-activate the GET
  4089.  
  4090.       ENDIF
  4091.  
  4092.    ENDIF
  4093.  
  4094.    RETURN (NIL)
  4095.  
  4096.  
  4097. *
  4098. FUNCTION IncrGetApplyKey(oGet ,;   // Get object
  4099.                          nKey  ;   // Key to be applied
  4100.                         )
  4101.                              // Incremental Get apply key for + and - keys
  4102.  
  4103.    LOCAL xValue              // Temporary value
  4104.  
  4105.    DO CASE
  4106.  
  4107.       CASE nKey == 43        // + Key
  4108.  
  4109.            IF oGet:type$'ND' // Applicable only on numerics and dates gets
  4110.  
  4111.                              // Grab value from edit buffer
  4112.               xValue := oGet:unTransform()
  4113.  
  4114.               xValue++       // Increment
  4115.  
  4116.                              // Tansform, track change, display new value
  4117.               oGet:buffer  := TRANSFORM(xValue,oGet:picture)
  4118.               oGet:changed := .T.
  4119.               oGet:display()
  4120.  
  4121.            ENDIF
  4122.  
  4123.       CASE nKey == 45        // - key
  4124.  
  4125.            IF oGet:type$'ND' // Applicable only on numerics and dates gets
  4126.  
  4127.                              // Grab value from edit buffer
  4128.               xValue := oGet:unTransform()
  4129.  
  4130.               xValue--       // Decrement
  4131.  
  4132.                              // Tansform, track change, display new value
  4133.               oGet:buffer  := TRANSFORM(xValue,oGet:picture)
  4134.               oGet:changed := .T.
  4135.               oGet:display()
  4136.  
  4137.            ENDIF
  4138.  
  4139.  
  4140.       OTHERWISE
  4141.                              // For all other key, use standard GetApplyKey()
  4142.          GetApplyKey(oGet,nKey)
  4143.  
  4144.    ENDCASE
  4145.  
  4146.    RETURN (NIL)
  4147.  
  4148.  
  4149. *
  4150. FUNCTION IncreButton(oGet        ,; // Get linked to the incremental button
  4151.                      aWinButtons ,; // List of related buttons
  4152.                      aGetList     ; // List of related gets
  4153.                     )
  4154.  
  4155.                              // Add a button to manage incremental action
  4156.    @ FONT_SIZE_X * COL()                        ,;
  4157.      FONT_SIZE_Y * ROW()                       ,,;
  4158.      BUTTON                                      ;
  4159.      STYLE BUTTON_TYPE_REPEAT                    ;
  4160.      ACTION { |x,y,but| IncreVal(x,y,but,oGet) } ;
  4161.      DISPLAYUP aBmpBase[ARROW_G_UP]              ;
  4162.      DISPLAYDN aBmpBase[ARROW_G_DW]              ;
  4163.      CARGO aGetList                              ;
  4164.      ATTACH aWinButtons
  4165.  
  4166.    RETURN (NIL)
  4167.  
  4168.  
  4169. *
  4170. STATIC FUNCTION IncreVal(nMouseX ,;
  4171.                          nMouseY ,;
  4172.                          aButton ,;
  4173.                          oGet     ;
  4174.                         )
  4175.  
  4176.                              // This function is called by the incremental button
  4177.                              // from a get. You must note two things. 1st, the
  4178.                              // get linked to this button is not always the focused
  4179.                              // get, so we must work on the variable and not on
  4180.                              // the buffer, 2nd, as the button must be a repeat
  4181.                              // button we dont give the hand back to the reader so
  4182.                              // we must manage prevalidation and postvalidation
  4183.                              // at this level
  4184.  
  4185.    LOCAL nRow     := 0       // Define some environnement variables
  4186.    LOCAL nCol     := 0
  4187.    LOCAL nSaveCur := 0
  4188.    LOCAL xOldVal  := 0       // Previous value to restore if needed
  4189.    LOCAL xVal     := 0       // Value to be incremented
  4190.  
  4191.  
  4192.                              // Allow modifications only when Get type is N or D;
  4193.                              // and when clause, if exists, is .T.
  4194.    IF (oGet:type$'ND') .AND. ( oGet:preBlock == NIL ) .OR. EVAL( oGet:preBlock, oGet )
  4195.  
  4196.  
  4197.       nRow     := ROW()      // Save cursor shape and location
  4198.       nCol     := COL()
  4199.       nSaveCur := SETCURSOR(0)
  4200.  
  4201.                              // If get is focused
  4202.       IF oGet:hasfocus
  4203.                              // Work on the buffer
  4204.          xOldVal := oGet:UnTransform()
  4205.  
  4206.       ELSE
  4207.                              // Else work on the variable
  4208.          xOldVal := oGet:varget()
  4209.  
  4210.       ENDIF
  4211.  
  4212.       xVal     := xOldVal    // Store for futur value
  4213.  
  4214.                              // Add or substract depending on clic location
  4215.                              // on the top of button add 1, on the bottom
  4216.                              // substact 1
  4217.       xVal += IF((oGet:row+0.5)*FONT_SIZE_Y<nMouseY,-1,1)
  4218.  
  4219.       oGet:varput(xVal)      // Store the new value in the variable
  4220.  
  4221.                              // Set variable value if valid clause, when
  4222.                              // exist, is .T.
  4223.       IF !( oGet:postBlock == NIL ) .AND. !EVAL( oGet:postBlock, oGet )
  4224.  
  4225.                              // Valid clause is .F., restore old value
  4226.          oGet:varput(xOldVal)
  4227.  
  4228.       ELSE
  4229.  
  4230.                              // Tranform and redisplay value
  4231.          oGet:buffer:=TRANSFORM(xVal,oGet:picture)
  4232.          oGet:display()
  4233.  
  4234.          oGet:changed := .T. // Get has changed
  4235.  
  4236.       ENDIF
  4237.  
  4238.                              // Restore cusor shape and location
  4239.       DEVPOS(nRow,nCol)
  4240.       SETCURSOR(nSaveCur)
  4241.  
  4242.    ENDIF
  4243.  
  4244.    RETURN (NIL)
  4245.  
  4246. *
  4247.                              // Group Extended Gets - DROPBOXL GETS
  4248.                              // Note : Here are some very simples
  4249.                              // CA-CLIPPER generics functions to extend
  4250.                              // GET/READ capability
  4251. /***
  4252. *
  4253. *  DropGetReader()      Special reader for dropbox gets
  4254. *  DropGetApplyKey()    Dropbox Get apply key
  4255. *  DropButton()         Define a button to allow drop action on a get
  4256. *  xGetDropBox()        Action to be executed when dropbox button is down
  4257. *
  4258. *  xDropBoxBrowse()     Browse on a mono dim array (equiv to aChoice())
  4259. *  nDropBoxSkipper()    Skip inside a browse array
  4260. *  DropBrowseVert()     Manage vertical scrollbar percentage
  4261. *
  4262. */
  4263.  
  4264. *
  4265. FUNCTION DropGetReader(oGet         ,;  // Object to be read
  4266.                        aGetList     ,;  // Related gets objects
  4267.                        aCtrlButtons ,;  // Related buttons
  4268.                        aDropValues  ,;  // Values available in the drop box
  4269.                        bDropSpecial  ;  // Block to allow special DropBoxes
  4270.                       )
  4271.                              // Special reader for drop box Get
  4272.  
  4273.                              // Needs some variables to manage Mouse and buttons
  4274.    LOCAL nKey
  4275.    LOCAL nCurrentGet
  4276.  
  4277.  
  4278.                              // Record reference of current get in GetList
  4279.    nCurrentGet := Ascan(aGetList, {|o| o==oGet })
  4280.  
  4281.                              // If needed, reach the requested get
  4282.    IF !(nHitGet()==NIL) .AND. nCurrentGet<>nHitGet()
  4283.  
  4284.       IF nCurrentGet > nHitGet()
  4285.          oGet:exitstate := GE_UP
  4286.       ELSE
  4287.          oGet:exitstate := GE_DOWN
  4288.       ENDIF
  4289.  
  4290.    ELSE
  4291.  
  4292.                              // Reset GetGoTo Set/Get function
  4293.       nHitGet(NIL)
  4294.  
  4295.                              // Read the GET if the WHEN condition is satisfied
  4296.       IF ( GetPreValidate( oGet ) )
  4297.  
  4298.                              // Activate the GET for reading
  4299.          oGet:setFocus()
  4300.  
  4301.          WHILE ( oGet:exitState == GE_NOEXIT )
  4302.  
  4303.                              // Check for initial typeout (no editable positions)
  4304.             IF ( oGet:typeOut )
  4305.                oGet:exitState := GE_ENTER
  4306.             ENDIF
  4307.  
  4308.  
  4309.                              // Apply keystrokes until exit
  4310.             WHILE ( oGet:exitState == GE_NOEXIT )
  4311.  
  4312.                nKey := mInkey( 0 ,aCtrlButtons ,aGetList )
  4313.  
  4314.                IF nKey == K_BUTTON .OR. nKey == K_ACCELERATOR
  4315.  
  4316.                              // Nothing To do
  4317.  
  4318.                ELSEIF nKey == K_GET
  4319.  
  4320.                   IF nCurrentGet > nHitGet()
  4321.                              // Get field clicked is up
  4322.                      oGet:exitState := GE_UP
  4323.                   ELSEIF nCurrentGet < nHitGet()
  4324.                              // Get field clicked is down
  4325.                      oGet:exitState := GE_DOWN
  4326.                   ENDIF
  4327.  
  4328.                ELSE
  4329.                              // Apply the key to the get object
  4330.                   DropGetApplyKey( oGet, nKey, aDropValues, bDropSpecial )
  4331.  
  4332.                ENDIF
  4333.  
  4334.             ENDDO
  4335.  
  4336.                              // Disallow exit if the VALID condition
  4337.                              // is not satisfied
  4338.             IF ( !GetPostValidate( oGet ) )
  4339.                oGet:exitState := GE_NOEXIT
  4340.             ENDIF
  4341.  
  4342.          ENDDO
  4343.  
  4344.          oGet:killFocus()    // De-activate the GET
  4345.  
  4346.       ENDIF
  4347.  
  4348.    ENDIF
  4349.  
  4350.    RETURN (NIL)
  4351.  
  4352.  
  4353. *
  4354. FUNCTION DropGetApplyKey(oGet         ,;   // Get object
  4355.                          nKey         ,;   // Key to be applied
  4356.                          aDropValues  ,;   // Values available in drop box
  4357.                          bDropSpecial  ;   // It is a classical autodropbox
  4358.                         )
  4359.                              // Dropbox apply key
  4360.  
  4361.    DO CASE
  4362.  
  4363.       CASE nKey == K_ENTER   // Enter ==> DropBox
  4364.  
  4365.            IF bDropSpecial==NIL
  4366.  
  4367.               xGetDropBox(0, 0, NIL, aDropValues, oGet )
  4368.  
  4369.            ELSE
  4370.  
  4371.               xDropSpecial(0, 0, NIL, oGet, bDropSpecial)
  4372.  
  4373.            ENDIF
  4374.  
  4375.       OTHERWISE
  4376.                              // For all other key, use standard GetApplyKey()
  4377.          GetApplyKey(oGet,nKey)
  4378.  
  4379.    ENDCASE
  4380.  
  4381.    RETURN (NIL)
  4382.  
  4383.  
  4384. *
  4385. FUNCTION DropButton(oGet        ,; // Get linked to the incremental button
  4386.                     aWinButtons ,; // List of related buttons
  4387.                     aGetList    ,; // List of related gets
  4388.                     bDropBox     ;
  4389.                    )
  4390.  
  4391.                              // Add a button to manage drop box action
  4392.    @ FONT_SIZE_X * COL()                              ,;
  4393.      FONT_SIZE_Y * ROW()                             ,,;
  4394.      BUTTON                                            ;
  4395.      STYLE BUTTON_TYPE_RELEASE                         ;
  4396.      ACTION bDropBox                                   ;
  4397.      DISPLAYUP aBmpBase[DROPBOX_UP]                    ;
  4398.      DISPLAYDN aBmpBase[DROPBOX_DW]                    ;
  4399.      CARGO oGet                                        ;
  4400.      ATTACH aWinButtons
  4401.  
  4402.  
  4403.  
  4404.    RETURN (NIL)
  4405.  
  4406. *
  4407. FUNCTION xDropSpecial(nMouseX      ,; // Mouse location
  4408.                       nMouseY      ,; //
  4409.                       aButton      ,; // Button reference
  4410.                       oGet         ,; // Get object
  4411.                       bDropSpecial  ; // Special drop box block
  4412.                      )
  4413.  
  4414.  
  4415.    LOCAL nRow     := 0       // Define some environnement variables
  4416.    LOCAL nCol     := 0
  4417.    LOCAL nSaveCur := 0
  4418.    LOCAL xOldVal  := 0       // Previous value to restore if needed
  4419.    LOCAL xVal     := 0       // Value to be incremented
  4420.  
  4421.  
  4422.    IF oGet == NIL
  4423.       oGet     := aButton[BUTTON_CARGO]
  4424.    ENDIF
  4425.                              // Allow modifications only when when clause,
  4426.                              // if exists, is .T.
  4427.    IF ( oGet:preBlock == NIL ) .OR. EVAL( oGet:preBlock, oGet )
  4428.  
  4429.  
  4430.       nRow     := ROW()      // Save cursor shape and location
  4431.       nCol     := COL()
  4432.       nSaveCur := SETCURSOR(0)
  4433.  
  4434.                              // If get is focused
  4435.       IF oGet:hasfocus
  4436.                              // Work on the buffer
  4437.          xOldVal := oGet:UnTransform()
  4438.  
  4439.       ELSE
  4440.                              // Else work on the variable
  4441.          xOldVal := oGet:varget()
  4442.  
  4443.       ENDIF
  4444.  
  4445.       xVal     := xOldVal    // Store for futur value
  4446.  
  4447.                              // Eval special block to retrieve value
  4448.       xVal     := EVAL(bDropSpecial,oGet:row,oGet:col,oGet:row,oGet:row,xVal)
  4449.  
  4450.       IF xVal <> NIL         // Something selected
  4451.  
  4452.                              // Store the new value in the variable
  4453.          oGet:varput(xVal)
  4454.  
  4455.                              // Set variable value if valid clause, when
  4456.                              // exist, is .T.
  4457.          IF !( oGet:postBlock == NIL ) .AND. !EVAL( oGet:postBlock, oGet )
  4458.  
  4459.                               // Valid clause is .F., restore old value
  4460.             oGet:varput(xOldVal)
  4461.  
  4462.          ELSE
  4463.  
  4464.                               // Tranform and redisplay value
  4465.             oGet:buffer:=TRANSFORM(xVal,oGet:picture)
  4466.             oGet:display()
  4467.  
  4468.             oGet:changed := .T. // Get has changed
  4469.  
  4470.          ENDIF
  4471.  
  4472.       ENDIF
  4473.  
  4474.                              // Restore cusor shape and location
  4475.       DEVPOS(nRow,nCol)
  4476.       SETCURSOR(nSaveCur)
  4477.  
  4478.    ENDIF
  4479.  
  4480.    RETURN (NIL)
  4481.  
  4482.  
  4483.  
  4484.  
  4485.  
  4486. *
  4487. FUNCTION xGetDropBox(nMouseX     ,; //
  4488.                      nMouseY     ,;
  4489.                      aButton     ,;
  4490.                      aDropValues ,;
  4491.                      oGet         ;
  4492.                     )
  4493.  
  4494.    LOCAL nRow     := 0       // Define some environnement variables
  4495.    LOCAL nCol     := 0
  4496.    LOCAL nSaveCur := 0
  4497.    LOCAL xOldVal  := 0       // Previous value to restore if needed
  4498.    LOCAL xVal     := 0       // Value to be incremented
  4499.    LOCAL nTop     := 0
  4500.    LOCAL nRight   := 0
  4501.  
  4502.  
  4503.    IF oGet == NIL
  4504.       oGet     := aButton[BUTTON_CARGO]
  4505.    ENDIF
  4506.                              // Allow modifications only when when clause,
  4507.                              // if exists, is .T.
  4508.    IF ( oGet:preBlock == NIL ) .OR. EVAL( oGet:preBlock, oGet )
  4509.  
  4510.  
  4511.       nRow     := ROW()      // Save cursor shape and location
  4512.       nCol     := COL()
  4513.       nSaveCur := SETCURSOR(0)
  4514.  
  4515.                              // If get is focused
  4516.       IF oGet:hasfocus
  4517.                              // Work on the buffer
  4518.          xOldVal := oGet:UnTransform()
  4519.  
  4520.       ELSE
  4521.                              // Elsse work on the variable
  4522.          xOldVal := oGet:varget()
  4523.  
  4524.       ENDIF
  4525.  
  4526.       xVal     := xOldVal    // Store for futur value
  4527.  
  4528.                              // Set the row just under the get row
  4529.       nTop     := oGet:row + 1
  4530.                              // Align Box and drop down button on the right
  4531.       nRight   := oGet:Col+Len(Transform(oGet:Varget(),oGet:picture))+1
  4532.  
  4533.       xVal     := xDropBoxBrowse(nTop,NIL,NIL,nRight,aDropValues,xVal)
  4534.  
  4535.       IF xVal <> NIL         // Something selected
  4536.  
  4537.                              // Store the new value in the variable
  4538.          oGet:varput(xVal)
  4539.  
  4540.                              // Set variable value if valid clause, when
  4541.                              // exist, is .T.
  4542.          IF !( oGet:postBlock == NIL ) .AND. !EVAL( oGet:postBlock, oGet )
  4543.  
  4544.                               // Valid clause is .F., restore old value
  4545.             oGet:varput(xOldVal)
  4546.  
  4547.          ELSE
  4548.  
  4549.                               // Tranform and redisplay value
  4550.             oGet:buffer:=TRANSFORM(xVal,oGet:picture)
  4551.             oGet:display()
  4552.  
  4553.             oGet:changed := .T. // Get has changed
  4554.  
  4555.          ENDIF
  4556.  
  4557.       ENDIF
  4558.  
  4559.                              // Restore cusor shape and location
  4560.       DEVPOS(nRow,nCol)
  4561.       SETCURSOR(nSaveCur)
  4562.  
  4563.    ENDIF
  4564.  
  4565.    RETURN (NIL)
  4566.  
  4567. *
  4568. FUNCTION xDropBoxBrowse(nTop       ,; // Coordinates in rows and columns
  4569.                         nLeft      ,;
  4570.                         nBottom    ,;
  4571.                         nRight     ,;
  4572.                         aValues    ,; // List of caracters values
  4573.                         xInitValue  ; // Initial value
  4574.                        )
  4575.  
  4576.                              // Browse on a mono dim array (equiv to aChoice())
  4577.  
  4578.    LOCAL xSaveScreen := NIL
  4579.    LOCAL cSaveColor  := SETCOLOR("N/W+,W+/N")
  4580.    LOCAL nSaveCursor := SETCURSOR(0)
  4581.    LOCAL nSaveRow    := ROW()
  4582.    LOCAL nSaveCol    := COL()
  4583.  
  4584.    LOCAL oBrowse             // The TBrowse object
  4585.    LOCAL nKey        := 0    // Keystroke
  4586.    LOCAL nI          := 0    // Indice
  4587.    LOCAL nJ          := 0    // Indice
  4588.    LOCAL lMore       := .T.  // Loop control
  4589.    LOCAL lSelected   := .F.  // Something selected
  4590.    LOCAL lNeedVertBar:= .F.  // Do we need a vertical Scrollbar
  4591.    LOCAL nColWidth   := 0    // Column width
  4592.  
  4593.    LOCAL aWinButtons  := {}  // Arrays to handle buttons
  4594.    LOCAL aVertScroll  := {}  //        and scrolls bars
  4595.  
  4596.                              // We need to determine best location
  4597.    IF nLeft == NIL .AND. nBottom == NIL
  4598.  
  4599.       nBottom := MIN(nTop+LEN(aValues)+1,gMode()[LLG_MODE_TEXT_ROW] - 1)
  4600.  
  4601.       IF nBottom - nTop < 5  // Not enought lines to fit downward, fit upward
  4602.  
  4603.          nBottom := nTop - 2
  4604.          nTop    := 0
  4605.  
  4606.       ENDIF
  4607.  
  4608.                              // Do we need a vertical scrollbar
  4609.       lNeedVertBar := ( (nBottom-1) - (nTop+1) + 1 ) < LEN(aValues)
  4610.  
  4611.       AEVAL(aValues,{ |el| nColWidth := MAX(nColWidth,LEN(el)) } )
  4612.  
  4613.       nLeft := nRight - 2 - IF(lNeedVertBar,2,0) - nColWidth - 2 + 1
  4614.  
  4615.  
  4616.    ELSE
  4617.  
  4618.                              // Do we need a vertical scrollbar
  4619.       lNeedVertBar := ( (nBottom-1) - (nTop+1) + 1 ) < LEN(aValues)
  4620.  
  4621.  
  4622.    ENDIF
  4623.  
  4624.  
  4625.                              // Save screen
  4626.    xSaveScreen := SAVESCREEN(nTop, nLeft, nBottom, nRight)
  4627.                              // Display 3D box
  4628.    DISPBOX(nTop,nLeft,nBottom,nRight,LLG_BOX_GRAY_SQUARE)
  4629.  
  4630.  
  4631.                              // Compute the column width
  4632.    nColWidth := ( nRight - IF(lNeedVertBar,4,2) ) - ( nLeft + 2 ) + 1
  4633.  
  4634.                              // Create a new browse object
  4635.    oBrowse := TBrowseNew( nTop+1, nLeft+2, nBottom-1, nRight-IF(lNeedVertBar,4,2) )
  4636.  
  4637.                              // Use cargo to store pointer on aValues and
  4638.                              // nRowPtr (equivalent to the RECNO())
  4639.    oBrowse:cargo := { aValues , 1 }
  4640.                              // Use some translate to make it clearer
  4641.    #XTRANSLATE :aValues   => :cargo\[1\]
  4642.    #XTRANSLATE :nRowPtr   => :cargo\[2\]
  4643.  
  4644.  
  4645.                              // Compute the column width
  4646.    nColWidth := ( nRight - IF(lNeedVertBar,4,2) ) - ( nLeft + 2 ) + 1
  4647.  
  4648.                              // Add the column to the browse
  4649.    oBrowse:addColumn( TBColumnNew('',{ || PADR(aValues[oBrowse:nRowPtr],nColWidth) } ) )
  4650.  
  4651.  
  4652.                              // Use a custom 'skipper' to handle arrays moves
  4653.    oBrowse:skipBlock := { |x| nDropBoxSkipper( x, oBrowse ) }
  4654.  
  4655.                              // Change the heading and column separators
  4656.    oBrowse:headSep := ''
  4657.    oBrowse:colSep  := ''
  4658.  
  4659.    IF lNeedVertBar           // If we need a vertical scroll bar
  4660.  
  4661.                              // Add vertical scroll bar
  4662.       @ (nRight-3)*FONT_SIZE_X                                              ,;
  4663.         (nTop+1)*FONT_SIZE_Y                                                ,;
  4664.         (nRight-1)*FONT_SIZE_X                                              ,;
  4665.         nBottom*FONT_SIZE_Y                                                  ;
  4666.         SCROLLBAR                                                            ;
  4667.         STYLE BUTTON_TYPE_SCROLL_VERT                                        ;
  4668.         ACTIONUP  { || oBrowse:stabilize() }                                 ;
  4669.         ACTIONDN  { || oBrowse:stabilize() }                                 ;
  4670.         ACTIONBAR { |nSens,nPercent| DropBrowseVert(nSens,nPercent,oBrowse)} ;
  4671.         HANDLE aVertScroll                                                   ;
  4672.         ATTACH aWinButtons
  4673.  
  4674.    ENDIF
  4675.  
  4676.                              // Add a large button size equal
  4677.                              // to browse size to handle clics
  4678.                              // inside the browse.
  4679.                              // Nothing to draw inside the button !!
  4680.    @ (nLeft+2 )*FONT_SIZE_X                                            ,;
  4681.      (nTop+1  )*FONT_SIZE_Y                                            ,;
  4682.      (nRight-IF(lNeedVertBar,3,1))*FONT_SIZE_X                         ,;
  4683.      nBottom*FONT_SIZE_Y                                                ;
  4684.      BUTTON                                                             ;
  4685.      STYLE BUTTON_TYPE_RELEASE                                          ;
  4686.      ACTION { |nMouseX,nMouseY| BrowseClic(nMouseX,nMouseY,oBrowse,0),lSelected := .T., lMore := .F. } ;
  4687.      ATTACH aWinButtons
  4688.  
  4689.                              // Add a close window button
  4690.    @ nLeft*FONT_SIZE_X                       ,;
  4691.      nTop *FONT_SIZE_Y                      ,,;
  4692.      BUTTON                                   ;
  4693.      STYLE BUTTON_TYPE_KEY                    ;
  4694.      ACTION K_ESC                             ;
  4695.      DISPLAYUP aBmpBase[CLOSWIN_UP]           ;
  4696.      DISPLAYDN aBmpBase[CLOSWIN_DW]           ;
  4697.      ATTACH aWinButtons
  4698.  
  4699.  
  4700.                              // Show all buttons defined
  4701.    SHOW ALL BUTTONS aWinButtons
  4702.  
  4703.  
  4704.                              // Find initial position
  4705.    IF (nJ := ASCAN(aValues,xInitValues))==0
  4706.       nJ := 1
  4707.    ENDIF
  4708.  
  4709.                              // Go to initial position
  4710.    IF lNeedVertBar
  4711.  
  4712.       oBrowse:nRowPtr := nJ
  4713.  
  4714.    ELSE
  4715.  
  4716.       FOR nI := 1 TO nJ-1
  4717.           oBrowse:down()
  4718.       NEXT nI
  4719.  
  4720.    ENDIF
  4721.  
  4722.                              // Main loop
  4723.    WHILE lMore
  4724.  
  4725.       // Don't let the cursor move into frozen columns
  4726.       IF ( oBrowse:colPos <= oBrowse:freeze )
  4727.          oBrowse:colPos := ( oBrowse:freeze + 1 )
  4728.  
  4729.       ENDIF
  4730.  
  4731.       // Stabilize the display until it's stable or until a key is pressed
  4732.       DO WHILE !oBrowse:Stabilize() .AND. NEXTKEY()==0
  4733.       ENDDO
  4734.  
  4735.       IF ( oBrowse:hitTop .or. oBrowse:hitBottom )
  4736.          TONE( 125, 0 )
  4737.  
  4738.       ENDIF
  4739.  
  4740.       IF lNeedVertBar .AND. NEXTKEY()==0
  4741.                              //  When the browse move, with up(),left()...
  4742.                              //  methods, we need to refresh scrollbars
  4743.                              //  locations. Refresh only if no key pending
  4744.          ScrBarUpDate(aVertScroll,DropBrowseVert(NIL,NIL,oBrowse))
  4745.  
  4746.       ENDIF
  4747.  
  4748.                              // Everything's done -- just wait for a key
  4749.       nKey := mInkey( 0 , aWinButtons )
  4750.  
  4751.       IF ( nKey == K_ESC )   // Esc means leave
  4752.          lMore := .F.
  4753.  
  4754.       ELSEIF ( nKey == K_BUTTON )   .OR. ;
  4755.              ( nKey == K_CLIC_OUT ) .OR. ;
  4756.              ( nKey == K_ACCELERATOR )
  4757.  
  4758.          //  Warning, when a button is hitted, mInkey() give the hand
  4759.          //  back to main calling routine, and a value of K_BUTTON is
  4760.          //  returned. We must not apply this K_BUTTON to applyKey
  4761.          //  K_CLIC_OUT is returned when the clic does not match
  4762.          //  any button. K_ACCELERATOR is returned when an accelerator
  4763.          //  key have been striked
  4764.          //  We dont need to apply these keys
  4765.  
  4766.       ELSE
  4767.  
  4768.          DO CASE
  4769.  
  4770.             CASE nKey == K_DOWN
  4771.                oBrowse:down()
  4772.  
  4773.             CASE nKey == K_PGDN
  4774.                oBrowse:pageDown()
  4775.  
  4776.             CASE nKey == K_CTRL_PGDN
  4777.                oBrowse:goBottom()
  4778.  
  4779.             CASE nKey == K_UP
  4780.                oBrowse:up()
  4781.  
  4782.             CASE nKey == K_PGUP
  4783.                oBrowse:pageUp()
  4784.  
  4785.             CASE nKey == K_CTRL_PGUP
  4786.                oBrowse:goTop()
  4787.  
  4788.             CASE nKey == K_RETURN
  4789.                              // Something selected
  4790.                  lSelected := .T.
  4791.                  lMore     := .F.
  4792.  
  4793.          ENDCASE
  4794.  
  4795.       ENDIF
  4796.  
  4797.    ENDDO
  4798.  
  4799.    DEVPOS(nSaveRow,nSaveCol)
  4800.    SETCURSOR(nSaveCursor)
  4801.    SETCOLOR(cSaveColor)
  4802.    RESTSCREEN(nTop, nLeft, nBottom, nRight,xSaveScreen)
  4803.  
  4804.  
  4805.    RETURN (IF(lSelected,oBrowse:aValues[oBrowse:nRowPtr],NIL))
  4806.  
  4807.  
  4808. *
  4809. STATIC FUNCTION nDropBoxSkipper(nSkip    ,;  // Number of lines to skip
  4810.                                 oBrowse   ;  // Browse object
  4811.                                )
  4812.                              // Skip inside a browse array
  4813.  
  4814.    LOCAL nI := 0
  4815.  
  4816.    DO CASE
  4817.  
  4818.       CASE ( nSkip > 0 .AND. !(oBrowse:nRowPtr==LEN(oBrowse:aValues)) )
  4819.  
  4820.          WHILE ( nI < nSkip )
  4821.                              // Skip Foward
  4822.  
  4823.             oBrowse:nRowPtr := oBrowse:nRowPtr + 1
  4824.  
  4825.             nI++
  4826.  
  4827.             IF (oBrowse:nRowPtr==LEN(oBrowse:aValues))
  4828.                              // End of array
  4829.                EXIT
  4830.  
  4831.             ENDIF
  4832.  
  4833.          ENDDO
  4834.  
  4835.  
  4836.       CASE ( nSkip < 0 .AND. !(oBrowse:nRowPtr==1) )
  4837.  
  4838.          WHILE ( nI > nSkip )
  4839.                              // Skip backward
  4840.  
  4841.             oBrowse:nRowPtr := oBrowse:nRowPtr - 1
  4842.  
  4843.             nI--
  4844.  
  4845.             IF oBrowse:nRowPtr == 1
  4846.                EXIT          // Begin of array
  4847.             ENDIF
  4848.  
  4849.  
  4850.          ENDDO
  4851.  
  4852.    ENDCASE
  4853.  
  4854.    RETURN (nI)
  4855.  
  4856. *
  4857. STATIC FUNCTION DropBrowseVert(nSens     ,;  // NIL, -1, 0, 1
  4858.                                nPercent  ,;  // NIL or 0 to 1
  4859.                                oBrowse    ;  // Browse pointer
  4860.                               )
  4861.  
  4862.                              // Manage vertical scrollbar percentage
  4863.  
  4864.    IF nSens <> NIL           // Move the pointer
  4865.  
  4866.       IF nSens == 0          // Set the position depending on %
  4867.          oBrowse:nRowPtr := MAX(1,INT(nPercent*LEN(oBrowse:aValues)))
  4868.          oBrowse:refreshAll()
  4869.  
  4870.       ELSEIF nSens == -1     // Move up
  4871.  
  4872.          oBrowse:up()
  4873.  
  4874.       ELSEIF nSens == 1      // Move down
  4875.  
  4876.          oBrowse:down()
  4877.  
  4878.       ENDIF
  4879.  
  4880.    ELSE                      // nSens==NIL just mean : what is location in %
  4881.  
  4882.    ENDIF
  4883.  
  4884.                              // Return location in %
  4885.    RETURN (oBrowse:nRowPtr/LEN(oBrowse:aValues))
  4886.  
  4887. *
  4888.                              // Group Extended Gets - RADIOS GETS
  4889.                              // Note : Here are some very simples
  4890.                              // CA-CLIPPER generics functions to extend
  4891.                              // GET/READ capability
  4892. /***
  4893. *
  4894. *  RadioAddGets()       Add gets corresponding to one radio get
  4895. *  RadioDisplay()       Display all gets corresponding to one radio get
  4896. *  RadioReader()        Special reader for radio Get
  4897. *  RadioApplyKey()      Radio Get apply keys
  4898. *  RadButDisp()         Display special buttons for radio gets
  4899. *  RadOnOff()           Switch radio button state
  4900. *  bLocalDetach()       Create detached local variables
  4901. *  GetBox()             Draw a 3D box arround gets
  4902. *
  4903. */
  4904.  
  4905. *
  4906. FUNCTION RadioAddGets(bSetGetVar     ,;  // Set Get block on master variable
  4907.                       cVar           ,;  // Variable name
  4908.                       aRadio         ,;  // List of values
  4909.                       aGetList       ,;  // Related gets
  4910.                       aCtrlButtons   ,;  // Related buttons
  4911.                       lHorizontal    ,;  // Display in horizontal | vertical
  4912.                       lEmptyAllowed   ;  // Allow an empty choice
  4913.                      )
  4914.  
  4915.                              // Add gets corresponding to one radio get
  4916.  
  4917.    LOCAL oGet                // Temporary get object
  4918.    LOCAL nGet         := 0   // Loop indice
  4919.  
  4920.                              // Number of radio buttons to create
  4921.    LOCAL nRadioGets   := LEN(aRadio)
  4922.  
  4923.                              // First radio button reference in GetList
  4924.    LOCAL nRadioFirst  := LEN(aGetList) + 1
  4925.  
  4926.                              // Cursor location
  4927.    LOCAL nRow         := ROW()
  4928.    LOCAL nCol         := COL()
  4929.  
  4930.  
  4931.    FOR nGet := 1 TO nRadioGets
  4932.                              // Loop on all choices availables
  4933.  
  4934.                              // Create a new empty GET object
  4935.        oGet := GETNEW()
  4936.                              // Add it to the Get List
  4937.        AADD(aGetList,oGet)
  4938.  
  4939.                              // Set the variable name
  4940.        oGet:name := cVar
  4941.  
  4942.                              // Create a Get block using a detached local
  4943.                              // variable. (Because we are in a loop and nGet
  4944.                              // will take the value nRadioGets+1 when we will
  4945.                              // exit ! )
  4946.        oGet:block := bLocalDetach(aRadio[nGet])
  4947.  
  4948.                              // We will store 3 elements in the GET cargo
  4949.                              // The real SetGet block , Pointers on the
  4950.                              // others GETS and the logical value for
  4951.                              // allowed empty results
  4952.        oGet:cargo := { bSetGetVar , ARRAY(nRadioGets) , lEmptyAllowed }
  4953.  
  4954.                              // Use some translate to make it clearer
  4955.        #XTRANSLATE :bSetGetVar    => :cargo\[1\]
  4956.        #XTRANSLATE :aRadioGets    => :cargo\[2\]
  4957.        #XTRANSLATE :lEmptyAllowed => :cargo\[3\]
  4958.  
  4959.                              // The second GET cargo element must be filled
  4960.                              // with associated GETS references
  4961.        AEVAL(oGet:aRadioGets , { |el,i| oGet:aRadioGets[i] := nRadioFirst + i - 1 } )
  4962.  
  4963.        IF lHorizontal        // If it is an horizontal radio group
  4964.  
  4965.                              // Set the get location
  4966.           oGet:col := nCol + 2
  4967.           oGet:row := nRow
  4968.                              // Go right depending on the len of each get
  4969.           nCol += 2 + Len(Transform(oGet:Varget(),oGet:picture)) + 1
  4970.  
  4971.        ELSE                  // It is a vertical radio group
  4972.  
  4973.                              // Set the get location
  4974.           oGet:col := nCol + 2
  4975.           oGet:row := nRow++
  4976.  
  4977.        ENDIF
  4978.  
  4979.                              // Set the reader to the RadioReader
  4980.        oGet:reader := { |oG,GetList,aButtons| RadioReader(oG,GetList,aButtons) }
  4981.        oGet:display()
  4982.  
  4983.                              // Add a button to manage radio
  4984.        @ FONT_SIZE_X * (oGet:col - 2 )                          ,;
  4985.          FONT_SIZE_Y * oGet:row                                 ,;
  4986.          FONT_SIZE_X * oGet:col - 1                             ,;
  4987.          FONT_SIZE_Y * ( oGet:row + 1 ) - 1                      ;
  4988.          BUTTON                                                  ;
  4989.          STYLE BUTTON_TYPE_RELEASE                               ;
  4990.          ACTION { |x,y,aButton| RadOnOff(x,y,aButton,aGetList) } ;
  4991.          DISPLAYUP { |nL,nT,nR,nB,xCargo| RadButDisp(nL,nT,nR,nB,xCargo,.T.,aGetList) } ;
  4992.          DISPLAYDN { |nL,nT,nR,nB,xCargo| RadButDisp(nL,nT,nR,nB,xCargo,.F.,aGetList) } ;
  4993.          CARGO LEN(aGetList)                                     ;
  4994.          ATTACH aCtrlButtons
  4995.  
  4996.  
  4997.    NEXT nGet
  4998.  
  4999.    RETURN (oGet)
  5000.  
  5001.  
  5002.  
  5003. *
  5004. FUNCTION RadioDisplay(oGet         ,; // Get linked to the radio button
  5005.                       aGetList      ; // List of related buttons
  5006.                      )
  5007.  
  5008.                              // Display all gets corresponding to one radio get
  5009.  
  5010.  
  5011.    LOCAL oGetTmp             // Temporary get object
  5012.    LOCAL nGet         := 0   // Loop indice
  5013.                              // Number of radio buttons to manage
  5014.    LOCAL nRadioGets   := LEN(oGet:aRadioGets)
  5015.  
  5016.  
  5017.    FOR nGet := 1 TO nRadioGets
  5018.                              // Loop on all choices availables
  5019.  
  5020.                              // Retrieve pointers on each get object
  5021.        oGetTmp := aGetList[oGet:aRadioGets[nGet]]
  5022.  
  5023.                              // Redisplay button in upper position
  5024.        RadButDisp(FONT_SIZE_X * (oGetTmp:col - 2 )            ,;
  5025.                   FONT_SIZE_Y * oGetTmp:row                   ,;
  5026.                   NIL                                         ,;
  5027.                   NIL                                         ,;
  5028.                   oGet:aRadioGets[nGet]                       ,;
  5029.                   .T.                                         ,;
  5030.                   aGetList                                     ;
  5031.                  )
  5032.  
  5033.    NEXT nGet
  5034.  
  5035.    RETURN (NIL)
  5036.  
  5037.  
  5038. *
  5039. FUNCTION RadioReader(oGet         ,;   // Get linked to the radio button
  5040.                      aGetList     ,;   // List of related buttons
  5041.                      aCtrlButtons  ;   // List of related gets
  5042.                     )
  5043.  
  5044.                              // Needs some variables to manage Mouse and buttons
  5045.  
  5046.    LOCAL nKey         := 0
  5047.    LOCAL nCurrentGet  := 0
  5048.  
  5049.  
  5050.                              // Record reference of current get in GetList
  5051.    nCurrentGet := Ascan(aGetList, {|o| o==oGet })
  5052.  
  5053.                              // If needed, reach the requested get
  5054.    IF !(nHitGet()==NIL) .AND. nCurrentGet<>nHitGet()
  5055.  
  5056.       IF nCurrentGet > nHitGet()
  5057.          oGet:exitstate := GE_UP
  5058.       ELSE
  5059.          oGet:exitstate := GE_DOWN
  5060.       ENDIF
  5061.  
  5062.    ELSE
  5063.  
  5064.                              // Reset GetGoTo Set/Get function
  5065.       nHitGet(NIL)
  5066.  
  5067.                              // Read the GET if the WHEN condition is satisfied
  5068.       IF ( GetPreValidate( oGet ) )
  5069.  
  5070.                              // Activate the GET for reading
  5071.          oGet:setFocus()
  5072.  
  5073.          WHILE ( oGet:exitState == GE_NOEXIT )
  5074.  
  5075.                              // Check for initial typeout
  5076.                              // (no editable positions)
  5077.             IF ( oGet:typeOut )
  5078.                oGet:exitState := GE_ENTER
  5079.             ENDIF
  5080.  
  5081.  
  5082.                              // Apply keystrokes until exit
  5083.                              // Replace all the DO WHILE/ENDDO original loop
  5084.             WHILE ( oGet:exitState == GE_NOEXIT )
  5085.  
  5086.                nKey := mInkey( 0 ,aCtrlButtons ,aGetList )
  5087.  
  5088.                IF nKey == K_BUTTON .OR. nKey == K_ACCELERATOR
  5089.  
  5090.                              // Nothing To do
  5091.  
  5092.                ELSEIF nKey == K_GET
  5093.  
  5094.                   IF nCurrentGet > nHitGet()
  5095.                              // Get field clicked is up
  5096.                      oGet:exitState := GE_UP
  5097.                   ELSEIF nCurrentGet < nHitGet()
  5098.                              // Get field clicked is down
  5099.                      oGet:exitState := GE_DOWN
  5100.                   ENDIF
  5101.  
  5102.                ELSE
  5103.                              // Apply the key to the get object
  5104.                   RadioApplyKey( oGet, nKey, aGetList )
  5105.  
  5106.                ENDIF
  5107.  
  5108.             ENDDO
  5109.  
  5110.                              // Disallow exit if the VALID condition
  5111.                              // is not satisfied
  5112.             IF ( !GetPostValidate( oGet ) )
  5113.                oGet:exitState := GE_NOEXIT
  5114.             ENDIF
  5115.  
  5116.          ENDDO
  5117.  
  5118.          oGet:killFocus()    // De-activate the GET
  5119.  
  5120.       ENDIF
  5121.  
  5122.    ENDIF
  5123.  
  5124.  
  5125.    RETURN (NIL)
  5126.  
  5127.  
  5128. *
  5129. FUNCTION RadioApplyKey(oGet, nKey, aGetList)
  5130.  
  5131.  
  5132.    LOCAL bKeyBlock
  5133.  
  5134.                              // Check for SET KEY first
  5135.    IF ( (bKeyBlock := SetKey(nKey)) <> NIL )
  5136.  
  5137.       GetDoSetKey(bKeyBlock, oGet)
  5138.       RETURN(NIL)
  5139.  
  5140.    ENDIF
  5141.  
  5142.  
  5143.    DO CASE
  5144.  
  5145.       CASE ( nKey == K_UP )
  5146.            oGet:exitState := GE_UP
  5147.  
  5148.       CASE ( nKey == K_SH_TAB )
  5149.            oGet:exitState := GE_UP
  5150.  
  5151.       CASE ( nKey == K_DOWN )
  5152.            oGet:exitState := GE_DOWN
  5153.  
  5154.       CASE ( nKey == K_TAB )
  5155.            oGet:exitState := GE_DOWN
  5156.  
  5157.       CASE ( nKey == K_ENTER )
  5158.            oGet:exitState := GE_ENTER
  5159.  
  5160.       CASE ( nKey == 32 )    // use space bar to toggle the radio button
  5161.  
  5162.            IF EVAL(oGet:bSetGetVar) == oGet:varget()
  5163.                              // If this get is the selected one
  5164.  
  5165.               IF oGet:lEmptyAllowed
  5166.                              // If it is allowed to reset all values
  5167.                              // deselect it
  5168.                  EVAL(oGet:bSetGetVar,'')
  5169.  
  5170.               ENDIF
  5171.  
  5172.            ELSE              // if this get is not selected, select it
  5173.  
  5174.               EVAL(oGet:bSetGetVar,oGet:varget())
  5175.  
  5176.  
  5177.            ENDIF
  5178.                              // Redisplay all RADIO GETS
  5179.            RadioDisplay( oGet , aGetList )
  5180.  
  5181.       CASE ( nKey == K_ESC )
  5182.            IF ( SET(_SET_ESCAPE) )
  5183.               oGet:undo()
  5184.               oGet:exitState := GE_ESCAPE
  5185.            ENDIF
  5186.  
  5187.       CASE ( nKey == K_PGUP )
  5188.            oGet:exitState := GE_WRITE
  5189.  
  5190.       CASE ( nKey == K_PGDN )
  5191.            oGet:exitState := GE_WRITE
  5192.  
  5193.       CASE ( nKey == K_CTRL_HOME )
  5194.            oGet:exitState := GE_TOP
  5195.  
  5196.  
  5197.       CASE (nKey == K_CTRL_W)
  5198.            oGet:exitState := GE_WRITE
  5199.  
  5200.       CASE (nKey == K_INS)
  5201.            SET( _SET_INSERT, !SET(_SET_INSERT) )
  5202.            ShowScoreboard()
  5203.  
  5204.    ENDCASE
  5205.  
  5206. RETURN (NIL)
  5207.  
  5208.  
  5209. *
  5210. FUNCTION RadButDisp(nLeft      ,; // Buttons pixels coordinates
  5211.                     nTop       ,; //
  5212.                     nRight     ,; //
  5213.                     nBottom    ,; //
  5214.                     nGet       ,; // Reference ofthe get in the GetList
  5215.                     lDisplayUp ,; // Display in up or down position
  5216.                     aGetList    ; // List of related Gets
  5217.                    )
  5218.  
  5219.  
  5220.    IF EVAL(aGetList[nGet]:bSetGetVar)==aGetList[nGet]:varget()
  5221.                              // If it is the selected get
  5222.  
  5223.       gBmpDisp(IF(lDisplayUp,aBmpBase[RADIO_F_UP],aBmpBase[RADIO_F_DW]),;
  5224.                nLeft                                                   ,;
  5225.                nTop                                                     ;
  5226.               )
  5227.  
  5228.    ELSE                      // If it is not the selected get
  5229.  
  5230.       gBmpDisp(IF(lDisplayUp,aBmpBase[RADIO_E_UP],aBmpBase[RADIO_E_DW]),;
  5231.                nLeft                                                   ,;
  5232.                nTop                                                     ;
  5233.               )
  5234.  
  5235.    ENDIF
  5236.  
  5237.  
  5238.    RETURN (NIL)
  5239.  
  5240.  
  5241.  
  5242. *
  5243. FUNCTION RadOnOff(nMouseX   ,;  // Mouse pixels locations
  5244.                   nMouseY   ,;  //
  5245.                   aButton   ,;  // Pointer on the button
  5246.                   aGetList   ;  // List of related get
  5247.                  )
  5248.  
  5249.                              // Switch radio button state
  5250.  
  5251.  
  5252.                              // Retrieve the get object using button cargo
  5253.                              // which contains the number of the get in the
  5254.                              // list
  5255.    LOCAL oGet := aGetList[aButton[BUTTON_CARGO]]
  5256.  
  5257.    IF EVAL(oGet:bSetGetVar) == oGet:varget()
  5258.                              // If it is the selected get
  5259.       IF oGet:lEmptyAllowed
  5260.                              // If it is allowed to reset all values
  5261.                              // deselect it
  5262.          EVAL(oGet:bSetGetVar,'')
  5263.  
  5264.       ENDIF
  5265.  
  5266.    ELSE                      // If it is deselected, select
  5267.  
  5268.       EVAL(oGet:bSetGetVar,oGet:varget())
  5269.  
  5270.    ENDIF
  5271.  
  5272.                              // Redisplay all RADIO GETS
  5273.    RadioDisplay( oGet , aGetList )
  5274.  
  5275.    RETURN (NIL)
  5276.  
  5277.  
  5278.  
  5279. *
  5280. FUNCTION bLocalDetach(xValue)
  5281.                              // Generic function to create detached locals
  5282.  
  5283.    RETURN ( { || xValue } )
  5284.  
  5285.  
  5286. *
  5287. FUNCTION GetBox(nTop       ,; // Box row/col coordinates
  5288.                 nLeft      ,; //
  5289.                 nBottom    ,; //
  5290.                 nRight     ,; //
  5291.                 nOffset    ,; // Frame offset
  5292.                 cTitle      ; // Box title (for a future use)
  5293.                )
  5294.  
  5295.                              // Draw a 3D box arround Gets
  5296.       LOCAL nGray  := 08
  5297.       LOCAL nWhite := 15
  5298.  
  5299.                              // Compute pixels coordinates
  5300.       nLeft   := nLeft   * FONT_SIZE_X - nOffset
  5301.       nTop    := nTop    * FONT_SIZE_Y - nOffset
  5302.       nRight  := (nRight + 1 )  * FONT_SIZE_X + nOffset - 1
  5303.       nBottom := (nBottom + 1 ) * FONT_SIZE_Y + nOffset - 1
  5304.  
  5305.                              // Draw lines
  5306.       gLine(nLeft         ,;
  5307.             nTop          ,;
  5308.             nRight        ,;
  5309.             nTop          ,;
  5310.             nGray         ,;
  5311.             LLG_MODE_SET   ;
  5312.           )
  5313.  
  5314.       gLine(nLeft         ,;
  5315.             nTop          ,;
  5316.             nLeft         ,;
  5317.             nBottom       ,;
  5318.             nGray         ,;
  5319.             LLG_MODE_SET   ;
  5320.           )
  5321.  
  5322.       gLine(nLeft  + 1    ,;
  5323.             nTop   + 1    ,;
  5324.             nRight - 1    ,;
  5325.             nTop   + 1    ,;
  5326.             nWhite        ,;
  5327.             LLG_MODE_SET   ;
  5328.           )
  5329.  
  5330.       gLine(nLeft   + 1   ,;
  5331.             nTop    + 1   ,;
  5332.             nLeft   + 1   ,;
  5333.             nBottom - 1   ,;
  5334.             nWhite        ,;
  5335.             LLG_MODE_SET   ;
  5336.           )
  5337.  
  5338.  
  5339.       gLine(nRight        ,;
  5340.             nTop    + 1   ,;
  5341.             nRight        ,;
  5342.             nBottom       ,;
  5343.             nWhite        ,;
  5344.             LLG_MODE_SET   ;
  5345.           )
  5346.  
  5347.       gLine(nRight        ,;
  5348.             nBottom       ,;
  5349.             nLeft   + 1   ,;
  5350.             nBottom       ,;
  5351.             nWhite        ,;
  5352.             LLG_MODE_SET   ;
  5353.           )
  5354.  
  5355.  
  5356.       gLine(nRight  - 1   ,;
  5357.             nTop    + 2   ,;
  5358.             nRight  - 1   ,;
  5359.             nBottom - 1   ,;
  5360.             nGray         ,;
  5361.             LLG_MODE_SET   ;
  5362.           )
  5363.  
  5364.       gLine(nRight  - 1   ,;
  5365.             nBottom - 1   ,;
  5366.             nLeft   + 2   ,;
  5367.             nBottom - 1   ,;
  5368.             nGray         ,;
  5369.             LLG_MODE_SET   ;
  5370.           )
  5371.  
  5372.    RETURN (NIL)
  5373.  
  5374.